diff --git a/CHANGELOG.md b/CHANGELOG.md
index a63ad7f..e1b7fc0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,12 +6,25 @@ KNOWN ISSUES
 
 RECENT CHANGES
 --------------
+
+- Logs sent by mail are easier to read
+        - Better subject (currently running or finished	run)
+        - Fixed	bogus double log sent in alert mails
+- Made unix signals posix compliant
+- Config file upgrade script now updates header
+! test if waitfortaskcompletion kill self works okay with osync
+- Improved batch runner
+- Made keep logging value configurable and not mandatory
+- Fixed handling of processes in uninterruptible sleep state
 ! update doc on sudoers paths
 - Parallelized sync functions
-	#TODO: explain bandwidth parameter, and CONFLICT_PREVALANCE option
+	- Rewrite sync resume process
+	! Remove conflict prevalance
+	- !doc about bandwidth
 - Added options to ignore permissions, ownership and groups
 - Refactored WaitFor... functions into one
 - Improved execution speed
+	- Rewrite sync resume process
 	- Added parallel execution for most secondary fuctions
 	- Lowered sleep time in wait functions
 	- Removed trivial sleep and forking in remote deletion code, send the whole function to background instead
@@ -20,7 +33,9 @@ RECENT CHANGES
 - Added KillAllChilds function to accept multiple pids
 - Improved logging
 
-XX xxx 2016: osync v1.1.2 released
+28 Aug 2016: osync v1.1.2 released
+- Renamed sync.conf to sync.conf.example (thanks to https://github.com/hortimech)
+- Fixed RunAfterHook may be executed twice
 - Fixed soft deletion when SUDO_EXEC is enabled
 
 06 Aug 2016: osync v1.1.1 released
diff --git a/CODING_STYLE.TXT b/CODING_STYLE.TXT
index 524c639..12e4c89 100644
--- a/CODING_STYLE.TXT
+++ b/CODING_STYLE.TXT
@@ -1,4 +1,4 @@
-Coding style used for my bash projects (v2.1 Oct 2015)
+Coding style used for my bash projects (v2.3 Sep 2016)
 
 ++++++ Header
 
@@ -8,7 +8,7 @@ Always use the following header
 #!/usr/bin/env bash
 
 PROGRAM="program-name" # Long description
-AUTHOR="(C) 20XX-20YY by Orsiris \"Ozy\" de Jong"
+AUTHOR="(C) 20XX-20YY by Orsiris de Jong"
 CONTACT="http://www.example.com me@example.com"
 PROGRAM_BUILD=YYYYMMDDVV
 
@@ -23,8 +23,8 @@ YYYYMMDDVV (Year, Month, Day, Revision): Example: 2015012402 = 2nd revision of 2
 Change old scripts with
 for i in $(grep -r '#!/bin/bash' * |cut -f1 -d':'); do sed -i 's&#!/bin/bash&#!/usr/bin/env bash&g' $i; done
 
-
 type instead of type -p for bash test (other shells don't know -p)
+
 ++++++ Indentation
 
 Using tabs
@@ -38,59 +38,78 @@ Some command # comment
 
 ++++++ Work comments
 
-Whenever there is some idea to postpone, use #TODO[-version]:[dev-name:] some remark
-A marker must be left where on the line a dev is working (when the work isn't finished). Marker is #WIP:dev-name: some remark
+Whenever there is some idea to postpone, use #TODO(priority):[dev-name:] some remark
+Priority can be critical, high, medium, low, verylow. No release can happen if there are TODOs other than low or verylow.
+Example: #TODO(high):deajan: need to do something
+
+A "work in progress" marker must be left on the line a dev is working when it's work isn't finished). Marker is #WIP:dev-name: some remark
 dev-name is mandatory if more than one person is coding
-Example: #TODO-v2.1:deajan: need to do something
+Example: #WIP:deajan: missing function something
 
 ++++++ Variables
 
-All local variables are lowercase, separated by _ (ex: low_wait)
-All global variables full upercase, separated by _ (ex: EXEC_TIME)
-All environment variables (verbose, silent, debug, etc) have prefix _ and are full upercase, separated by _ (ex: _PARANOIA_DEBUG)
+All local variables names have each first letter of the words uppercase and all others lowercase, except for the first word where all letters are lowercase
+Example: someLongVariable
+All global variables are full upercase, separated by _
+Example: EXEC_TIME
+All environment variables (verbose, silent, debug, etc) have prefix _ and are full upercase, separated by _
+Example: _PARANOIA_DEBUG
 
 ++++++ Functions
 
-Every word in a function begins with an uppercase (ex: SomeFunctionDoesThings)
+All function names should begin with an uppercase letter for every word, the other letters should be lowercase
+Example: SomeFunctionThatRocks
 
-Define functions this way. Use sed ':a;N;$!ba;s/\n{\n/ {\n/g' to adapt when opening bracket is on a new line.
+Bash does not provide any checks against missing function arguments. Also, missing quotes can lead to an inconsistent number of arguments.
+Most functions should have a first line that calls the special function __CheckArguments, which checks the number of given arguments for a function in order
+to find possible problems. Number of arguments are given as first argument to __CheckArguments. May be a number or a range, eg 0-2 if the function takes optional arguments.
+__CheckArguments will only trigger when the script is launched with _PARANOIA_DEBUG=yes. Also, it will only exist in the debug version.
+Use the following convention for function definition:
 
-function something {
-	
+function SomeFunction {
+	__CheckArguments 0 $# ${FUNCNAME[0]} "$@"               #__WITH_PARANOIA_DEBUG
+	...	
 }
 
-If function has some arguments, use local variable names that are more readable than $1...$n. Explain via comments what those variables contain if needed.
+Use sed ':a;N;$!ba;s/\n{\n/ {\n/g' to convert functions that have opening brackets on a new line.
 
-function anotherthing {
-	local var_name="${1}"
-	local other_var_name="${2}" # This variable contains stuff
+If the function has arguments, use local variable names that are more readable than $1...$n. Explain via comments what those variables contain if needed.
+Declare arguments before launching __CheckArguments:
+
+function AnotherFunction {
+	local varName="${1}"
+	local otherVarName="${2}" # This variable contains stuff
+	__CheckArguments 2 $# ${FUNCNAME[0]} "$@"		#__WITH_PARANOIA_DEBUG
+	...
 }
 
 Functions should always have return status
-function thirdthing {
-	some_command
+function RandomFunction {
+	...
 	return $?
 }
 
 ++++++ Sub functions
 
-When a function is a subroutine of another function, it is called _SomethingAsSubFunction
+When a function is a subroutine of another function, it is called _SomethingAsSubFunction:
+Example:
 
-++++++ Function argument check
+function _ApplyLocally
+function _ApplyRemotely
+function Apply
 
-Bash does not provide any checks against missing function arguments. Also, missing quotes can lead to an inconsistent number of arguments.
-Every function call will be checked by __CheckArguments which takes the number of arguments, $# (the real number of args given), the parent function name and the parent function's arguments.
-__CheckArguments will trigger a critical error if number of arguments if incorrect. This will also prevent silent typo errors.
-Ex:
+++++++ For and While statements
 
-function Something {
-	local some="${1}"
-	local other="${2}"
-	local args="${3}"
-	__CheckArguments 3 $# $FUNCNAME "$*"
+For and while statements will have the "do" part on the first line.
+Example:
 
-__CheckArguments will only trigger if script is called with DEBUG=yes
-Also, with PARANOIA_DEBUG=yes, __CheckArguments will recount all arguments given by "$*" and compare. This can mislead if arguments contain spaces.
+for i in "${var[@]}"; do
+	...
+done
+
+while [ $i -eq 1 ]; do
+	...
+done
 
 ++++++ If statements
 
@@ -106,7 +125,7 @@ fi
 
 A logging function is available with the following levels of logging:
 
-- DEBUG: Only log this when DEBUG flas is set in program. Any command forged for eval should be logged by this.
+- DEBUG: Only log this when DEBUG flas is set in program. Any command forged for eval instruction should be logged by this.
 - NOTICE: Standard messages
 - WARN: Requires attention
 - ERROR: Program produced an error but continues execution
@@ -128,7 +147,7 @@ cmd=$SSH_CMD' "some; commands \"'$VARIABLE'\" some; other; commands" > some_file
 ++++++ File variables
 
 All eval cmd should exit their content to a file called "$RUNDIR/osync.$FUNCNAME.$SCRIPT_PID"
-Dots are used instead of '_' so variables can be separated with a forbidden char in variables, so they get detected.
+Dots are used instead of '_' so variables can be separated with a forbidden char in variable names, so the separtors apply as wished.
 
 ++++++ Finding code errors
 
@@ -154,3 +173,11 @@ function FunctionName {
 #__ENDFUNC
 
 These functions are inserted into code that has placeholders like #__FUNC:FuncName
+
++++++++ Exit codes
+
+Normal exit code = 0
+Run with errors exit code = 1
+Run with warnings exit code = 2
+Wrong shell exit code = 127
+Usage function exit code = 128
diff --git a/README.md b/README.md
index 421c86e..1871e33 100644
--- a/README.md
+++ b/README.md
@@ -19,6 +19,9 @@ Osync provides the following capabilities
 - Batch runner for multiple sync tasks with rerun option for failed sync tasks
 - ACL synchronization
 
+osync is a state synchronizer. This means that it doesn't have to monitor files for changes. Instead, it compares replica lists between runs.
+A full run takes about 2 seconds on a local-local replication and about 10 seconds on a local-remote replication.
+Disabling some features file like attributes preservation and disk space checks may speed up execution. 
 osync uses a initiator / target sync schema. It can sync local to local or local to remote directories. By definition, initiator replica is always a local directory on the system osync runs on.
 osync uses pidlocks to prevent multiple concurrent sync processes on/to the same initiator / target replica.
 You may launch concurrent sync processes on the same system but only for different initiator replicas.
diff --git a/dev/debug_osync.sh b/dev/debug_osync.sh
index cdb9e71..6d0c483 100755
--- a/dev/debug_osync.sh
+++ b/dev/debug_osync.sh
@@ -1,13 +1,13 @@
 #!/usr/bin/env bash
 
 #TODO(critical): handle conflict prevalance, especially in sync_attrs function
-#TODO(critical): test new WaitForTaskCompletion behavior with self=true
+#TODO(critical): writelockfiles remote does not shut execution
 
 PROGRAM="osync" # Rsync based two way sync engine with fault tolerance
 AUTHOR="(C) 2013-2016 by Orsiris de Jong"
 CONTACT="http://www.netpower.fr/osync - ozy@netpower.fr"
 PROGRAM_VERSION=1.2-dev-parallel
-PROGRAM_BUILD=2016081902
+PROGRAM_BUILD=2016082201
 IS_STABLE=no
 
 #	Function Name		Is parallel	#__WITH_PARANOIA_DEBUG
@@ -47,7 +47,7 @@ IS_STABLE=no
 
 #### MINIMAL-FUNCTION-SET BEGIN ####
 
-## FUNC_BUILD=2016081805
+## FUNC_BUILD=2016082204
 ## BEGIN Generic functions for osync & obackup written in 2013-2016 by Orsiris de Jong - http://www.netpower.fr - ozy@netpower.fr
 
 ## type -p does not work on platforms other than linux (bash). If if does not work, always assume output is not a zero exitcode
@@ -230,7 +230,7 @@ function KillChilds {
 		# Try to kill nicely, if not, wait 15 seconds to let Trap actions happen before killing
 	if ( [ "$self" == true ] && kill -0 $pid > /dev/null 2>&1); then
 		Logger "Sending SIGTERM to process [$pid]." "DEBUG"
-		kill -s SIGTERM "$pid"
+		kill -s TERM "$pid"
 		if [ $? != 0 ]; then
 			sleep 15
 			Logger "Sending SIGTERM to process [$pid] failed." "DEBUG"
@@ -646,29 +646,6 @@ function WaitForTaskCompletion {
 
 	while [ ${#pidsArray[@]} -gt 0 ]; do
 		newPidsArray=()
-		for pid in "${pidsArray[@]}"; do
-			if kill -0 $pid > /dev/null 2>&1; then
-				# Handle uninterruptible sleep state or zombies by ommiting them from running process array (How to kill that is already dead ? :)
-				#TODO(high): have this tested on *BSD, Mac & Win
-				pidState=$(ps -p$pid -o state= 2 > /dev/null)
-				if [ "$pidState" != "D" ] && [ "$pidState" != "Z" ]; then
-					newPidsArray+=($pid)
-				fi
-			else
-				# pid is dead, get it's exit code from wait command
-				wait $pid
-				retval=$?
-				if [ $retval -ne 0 ]; then
-					errorcount=$((errorcount+1))
-					Logger "${FUNCNAME[0]} called by [$caller_name] finished monitoring [$pid] with exitcode [$result]." "DEBUG"
-					if [ "$WAIT_FOR_TASK_COMPLETION" == "" ]; then
-						WAIT_FOR_TASK_COMPLETION="$pid:$result"
-					else
-						WAIT_FOR_TASK_COMPLETION=";$pid:$result"
-					fi
-				fi
-			fi
-		done
 
 		Spinner
 		if [ $counting == true ]; then
@@ -708,6 +685,30 @@ function WaitForTaskCompletion {
 			fi
 		fi
 
+		for pid in "${pidsArray[@]}"; do
+			if kill -0 $pid > /dev/null 2>&1; then
+				# Handle uninterruptible sleep state or zombies by ommiting them from running process array (How to kill that is already dead ? :)
+				#TODO(high): have this tested on *BSD, Mac & Win
+				pidState=$(ps -p$pid -o state= 2 > /dev/null)
+				if [ "$pidState" != "D" ] && [ "$pidState" != "Z" ]; then
+					newPidsArray+=($pid)
+				fi
+			else
+				# pid is dead, get it's exit code from wait command
+				wait $pid
+				retval=$?
+				if [ $retval -ne 0 ]; then
+					errorcount=$((errorcount+1))
+					Logger "${FUNCNAME[0]} called by [$caller_name] finished monitoring [$pid] with exitcode [$result]." "DEBUG"
+					if [ "$WAIT_FOR_TASK_COMPLETION" == "" ]; then
+						WAIT_FOR_TASK_COMPLETION="$pid:$result"
+					else
+						WAIT_FOR_TASK_COMPLETION=";$pid:$result"
+					fi
+				fi
+			fi
+		done
+
 		pidsArray=("${newPidsArray[@]}")
 		sleep $SLEEP_TIME
 	done
@@ -1037,7 +1038,7 @@ function CheckConnectivity3rdPartyHosts {
 			for i in $REMOTE_3RD_PARTY_HOSTS
 			do
 				eval "$PING_CMD $i > /dev/null 2>&1" &
-				WaitForTaskCompletion $! 10 360 ${FUNCNAME[0]} true $KEEP_LOGGING
+				WaitForTaskCompletion $! 180 360 ${FUNCNAME[0]} true $KEEP_LOGGING
 				if [ $? != 0 ]; then
 					Logger "Cannot ping 3rd party host $i" "NOTICE"
 				else
@@ -1417,9 +1418,7 @@ function TrapQuit {
 		exitcode=2	# Warning exit code must not force daemon mode to quit
 	else
 		UnlockReplicas
-		if [ "$RUN_AFTER_CMD_ON_ERROR" == "yes" ]; then
-			RunAfterHook
-		fi
+		RunAfterHook
 		CleanUp
 		Logger "$PROGRAM finished." "NOTICE"
 		exitcode=0
@@ -1541,15 +1540,16 @@ function CheckReplicaPaths {
 
 	local pids
 
+	# Use direct comparaison before having a portable realpath implementation
 	#INITIATOR_SYNC_DIR_CANN=$(realpath "${INITIATOR[1]}")	#TODO(verylow): investigate realpath & readlink issues on MSYS and busybox here
 	#TARGET_SYNC_DIR_CANN=$(realpath "${TARGET[1]})
 
-	#if [ "$REMOTE_OPERATION" != "yes" ]; then
-	#	if [ "$INITIATOR_SYNC_DIR_CANN" == "$TARGET_SYNC_DIR_CANN" ]; then
-	#		Logger "Master directory [${INITIATOR[1]}] cannot be the same as target directory." "CRITICAL"
-	#		exit 1
-	#	fi
-	#fi
+	if [ "$REMOTE_OPERATION" != "yes" ]; then
+		if [ "${INITIATOR[1]}" == "${TARGET[1]}" ]; then
+			Logger "Initiator and target path [${INITIATOR[1]}] cannot be the same." "CRITICAL"
+			exit 1
+		fi
+	fi
 
 	_CheckReplicaPathsLocal "${INITIATOR[1]}" &
 	pids="$!"
@@ -2887,10 +2887,10 @@ function Init {
 
 	# Do not use exit and quit traps if osync runs in monitor mode
 	if [ $sync_on_changes -eq 0 ]; then
-		trap TrapStop SIGINT SIGHUP SIGTERM SIGQUIT
+		trap TrapStop INT HUP TERM QUIT
 		trap TrapQuit EXIT
 	else
-		trap TrapQuit SIGTERM EXIT SIGHUP SIGQUIT
+		trap TrapQuit TERM EXIT HUP QUIT
 	fi
 
 	local uri
diff --git a/dev/n_osync.sh b/dev/n_osync.sh
index f3c7669..a982ac4 100755
--- a/dev/n_osync.sh
+++ b/dev/n_osync.sh
@@ -1,13 +1,13 @@
 #!/usr/bin/env bash
 
 #TODO(critical): handle conflict prevalance, especially in sync_attrs function
-#TODO(critical): test new WaitForTaskCompletion behavior with self=true
+#TODO(critical): writelockfiles remote does not shut execution
 
 PROGRAM="osync" # Rsync based two way sync engine with fault tolerance
 AUTHOR="(C) 2013-2016 by Orsiris de Jong"
 CONTACT="http://www.netpower.fr/osync - ozy@netpower.fr"
 PROGRAM_VERSION=1.2-dev-parallel
-PROGRAM_BUILD=2016081902
+PROGRAM_BUILD=2016082201
 IS_STABLE=no
 
 #	Function Name		Is parallel	#__WITH_PARANOIA_DEBUG
@@ -99,9 +99,7 @@ function TrapQuit {
 		exitcode=2	# Warning exit code must not force daemon mode to quit
 	else
 		UnlockReplicas
-		if [ "$RUN_AFTER_CMD_ON_ERROR" == "yes" ]; then
-			RunAfterHook
-		fi
+		RunAfterHook
 		CleanUp
 		Logger "$PROGRAM finished." "NOTICE"
 		exitcode=0
@@ -223,15 +221,16 @@ function CheckReplicaPaths {
 
 	local pids
 
+	# Use direct comparaison before having a portable realpath implementation
 	#INITIATOR_SYNC_DIR_CANN=$(realpath "${INITIATOR[1]}")	#TODO(verylow): investigate realpath & readlink issues on MSYS and busybox here
 	#TARGET_SYNC_DIR_CANN=$(realpath "${TARGET[1]})
 
-	#if [ "$REMOTE_OPERATION" != "yes" ]; then
-	#	if [ "$INITIATOR_SYNC_DIR_CANN" == "$TARGET_SYNC_DIR_CANN" ]; then
-	#		Logger "Master directory [${INITIATOR[1]}] cannot be the same as target directory." "CRITICAL"
-	#		exit 1
-	#	fi
-	#fi
+	if [ "$REMOTE_OPERATION" != "yes" ]; then
+		if [ "${INITIATOR[1]}" == "${TARGET[1]}" ]; then
+			Logger "Initiator and target path [${INITIATOR[1]}] cannot be the same." "CRITICAL"
+			exit 1
+		fi
+	fi
 
 	_CheckReplicaPathsLocal "${INITIATOR[1]}" &
 	pids="$!"
@@ -1569,10 +1568,10 @@ function Init {
 
 	# Do not use exit and quit traps if osync runs in monitor mode
 	if [ $sync_on_changes -eq 0 ]; then
-		trap TrapStop SIGINT SIGHUP SIGTERM SIGQUIT
+		trap TrapStop INT HUP TERM QUIT
 		trap TrapQuit EXIT
 	else
-		trap TrapQuit SIGTERM EXIT SIGHUP SIGQUIT
+		trap TrapQuit TERM EXIT HUP QUIT
 	fi
 
 	local uri
diff --git a/dev/ofunctions.sh b/dev/ofunctions.sh
index f4bfd8f..32ae6ee 100644
--- a/dev/ofunctions.sh
+++ b/dev/ofunctions.sh
@@ -1,9 +1,13 @@
 #### MINIMAL-FUNCTION-SET BEGIN ####
 
-## FUNC_BUILD=2016081806
-## BEGIN Generic functions for osync & obackup written in 2013-2016 by Orsiris de Jong - http://www.netpower.fr - ozy@netpower.fr
+## FUNC_BUILD=2016082801
+## BEGIN Generic bash functions written in 2013-2016 by Orsiris de Jong - http://www.netpower.fr - ozy@netpower.fr
+
+## To use in a program, define the following variables:
+## PROGRAM=program-name
+## INSTANCE_ID=program-instance-name
+## _DEBUG=yes/no
 
-## type -p does not work on platforms other than linux (bash). If if does not work, always assume output is not a zero exitcode
 if ! type "$BASH" > /dev/null; then
 	echo "Please run this script only with bash shell. Tested on bash >= 3.2"
 	exit 127
@@ -28,6 +32,9 @@ fi
 ERROR_ALERT=0
 WARN_ALERT=0
 
+# Current log
+CURRENT_LOG=
+
 ## allow function call checks			#__WITH_PARANOIA_DEBUG
 if [ "$_PARANOIA_DEBUG" == "yes" ];then		#__WITH_PARANOIA_DEBUG
 	_DEBUG=yes				#__WITH_PARANOIA_DEBUG
@@ -49,6 +56,10 @@ SCRIPT_PID=$$
 LOCAL_USER=$(whoami)
 LOCAL_HOST=$(hostname)
 
+if [ "$PROGRAM" == "" ]; then
+	PROGRAM="ofunctions"
+fi
+
 ## Default log file until config file is loaded
 if [ -w /var/log ]; then
 	LOG_FILE="/var/log/$PROGRAM.log"
@@ -89,6 +100,7 @@ function _Logger {
 	local evalue="${3}" # What to log to stderr
 
 	echo -e "$lvalue" >> "$LOG_FILE"
+	CURRENT_LOG="$CURRENT_LOG"$'\n'"$lvalue"
 
 	if [ "$_LOGGER_STDERR" -eq 1 ]; then
 		cat <<< "$evalue" 1>&2
@@ -183,7 +195,7 @@ function KillChilds {
 		# Try to kill nicely, if not, wait 15 seconds to let Trap actions happen before killing
 	if ( [ "$self" == true ] && kill -0 $pid > /dev/null 2>&1); then
 		Logger "Sending SIGTERM to process [$pid]." "DEBUG"
-		kill -s SIGTERM "$pid"
+		kill -s TERM "$pid"
 		if [ $? != 0 ]; then
 			sleep 15
 			Logger "Sending SIGTERM to process [$pid] failed." "DEBUG"
@@ -220,11 +232,14 @@ function KillAllChilds {
 
 # osync/obackup/pmocr script specific mail alert function, use SendEmail function for generic mail sending
 function SendAlert {
-	__CheckArguments 0 $# ${FUNCNAME[0]} "$@"	#__WITH_PARANOIA_DEBUG
+	local runAlert="${1:-false}" # Specifies if current message is sent while running or at the end of a run
+
+	__CheckArguments 0-1 $# ${FUNCNAME[0]} "$@"	#__WITH_PARANOIA_DEBUG
 
 	local mail_no_attachment=
 	local attachment_command=
 	local subject=
+	local body=
 
 	# Windows specific settings
 	local encryption_string=
@@ -253,7 +268,8 @@ function SendAlert {
 	else
 		mail_no_attachment=0
 	fi
-	MAIL_ALERT_MSG="$MAIL_ALERT_MSG"$'\n\n'$(tail -n 50 "$LOG_FILE")
+	body="$MAIL_ALERT_MSG"$'\n\n'"$CURRENT_LOG"
+
 	if [ $ERROR_ALERT -eq 1 ]; then
 		subject="Error alert for $INSTANCE_ID"
 	elif [ $WARN_ALERT -eq 1 ]; then
@@ -262,11 +278,17 @@ function SendAlert {
 		subject="Alert for $INSTANCE_ID"
 	fi
 
+	if [ $runAlert == true ]; then
+		subject="Currently runing - $subject"
+	else
+		subject="Fnished run - $subject"
+	fi
+
 	if [ "$mail_no_attachment" -eq 0 ]; then
 		attachment_command="-a $ALERT_LOG_FILE"
 	fi
 	if type mutt > /dev/null 2>&1 ; then
-		echo "$MAIL_ALERT_MSG" | $(type -p mutt) -x -s "$subject" $DESTINATION_MAILS $attachment_command
+		echo "$body" | $(type -p mutt) -x -s "$subject" $DESTINATION_MAILS $attachment_command
 		if [ $? != 0 ]; then
 			Logger "Cannot send alert mail via $(type -p mutt) !!!" "WARN"
 		else
@@ -283,10 +305,10 @@ function SendAlert {
 		else
 			attachment_command=""
 		fi
-		echo "$MAIL_ALERT_MSG" | $(type -p mail) $attachment_command -s "$subject" $DESTINATION_MAILS
+		echo "$body" | $(type -p mail) $attachment_command -s "$subject" $DESTINATION_MAILS
 		if [ $? != 0 ]; then
 			Logger "Cannot send alert mail via $(type -p mail) with attachments !!!" "WARN"
-			echo "$MAIL_ALERT_MSG" | $(type -p mail) -s "$subject" $DESTINATION_MAILS
+			echo "$body" | $(type -p mail) -s "$subject" $DESTINATION_MAILS
 			if [ $? != 0 ]; then
 				Logger "Cannot send alert mail via $(type -p mail) without attachments !!!" "WARN"
 			else
@@ -300,7 +322,7 @@ function SendAlert {
 	fi
 
 	if type sendmail > /dev/null 2>&1 ; then
-		echo -e "Subject:$subject\r\n$MAIL_ALERT_MSG" | $(type -p sendmail) $DESTINATION_MAILS
+		echo -e "Subject:$subject\r\n$body" | $(type -p sendmail) $DESTINATION_MAILS
 		if [ $? != 0 ]; then
 			Logger "Cannot send alert mail via $(type -p sendmail) !!!" "WARN"
 		else
@@ -323,7 +345,7 @@ function SendAlert {
 		if [ "$SMTP_USER" != "" ] && [ "$SMTP_USER" != "" ]; then
 			auth_string="-auth -user \"$SMTP_USER\" -pass \"$SMTP_PASSWORD\""
 		fi
-		$(type mailsend.exe) -f $SENDER_MAIL -t "$DESTINATION_MAILS" -sub "$subject" -M "$MAIL_ALERT_MSG" -attach "$attachment" -smtp "$SMTP_SERVER" -port "$SMTP_PORT" $encryption_string $auth_string
+		$(type mailsend.exe) -f $SENDER_MAIL -t "$DESTINATION_MAILS" -sub "$subject" -M "$body" -attach "$attachment" -smtp "$SMTP_SERVER" -port "$SMTP_PORT" $encryption_string $auth_string
 		if [ $? != 0 ]; then
 			Logger "Cannot send mail via $(type mailsend.exe) !!!" "WARN"
 		else
@@ -339,7 +361,7 @@ function SendAlert {
 		else
 			SMTP_OPTIONS=""
 		fi
-		$(type -p sendemail) -f $SENDER_MAIL -t "$DESTINATION_MAILS" -u "$subject" -m "$MAIL_ALERT_MSG" -s $SMTP_SERVER $SMTP_OPTIONS > /dev/null 2>&1
+		$(type -p sendemail) -f $SENDER_MAIL -t "$DESTINATION_MAILS" -u "$subject" -m "$body" -s $SMTP_SERVER $SMTP_OPTIONS > /dev/null 2>&1
 		if [ $? != 0 ]; then
 			Logger "Cannot send alert mail via $(type -p sendemail) !!!" "WARN"
 		else
@@ -350,7 +372,7 @@ function SendAlert {
 
 	# pfSense specific
 	if [ -f /usr/local/bin/mail.php ]; then
-		echo "$MAIL_ALERT_MSG" | /usr/local/bin/mail.php -s="$subject"
+		echo "$body" | /usr/local/bin/mail.php -s="$subject"
 		if [ $? != 0 ]; then
 			Logger "Cannot send alert mail via /usr/local/bin/mail.php (pfsense) !!!" "WARN"
 		else
@@ -569,6 +591,8 @@ function joinString {
 # Time control function for background processes, suitable for multiple synchronous processes
 # Fills a global variable called WAIT_FOR_TASK_COMPLETION that contains list of failed pids in format pid1:result1;pid2:result2
 # Warning: Don't imbricate this function into another run if you plan to use the global variable output
+
+#TODO check missing local values used here
 function WaitForTaskCompletion {
 	local pids="${1}" # pids to wait for, separated by semi-colon
 	local soft_max_time="${2}" # If program with pid $pid takes longer than $soft_max_time seconds, will log a warning, unless $soft_max_time equals 0.
@@ -599,29 +623,6 @@ function WaitForTaskCompletion {
 
 	while [ ${#pidsArray[@]} -gt 0 ]; do
 		newPidsArray=()
-		for pid in "${pidsArray[@]}"; do
-			if kill -0 $pid > /dev/null 2>&1; then
-				# Handle uninterruptible sleep state or zombies by ommiting them from running process array (How to kill that is already dead ? :)
-				#TODO(high): have this tested on *BSD, Mac & Win
-				pidState=$(ps -p$pid -o state= 2 > /dev/null)
-				if [ "$pidState" != "D" ] && [ "$pidState" != "Z" ]; then
-					newPidsArray+=($pid)
-				fi
-			else
-				# pid is dead, get it's exit code from wait command
-				wait $pid
-				retval=$?
-				if [ $retval -ne 0 ]; then
-					errorcount=$((errorcount+1))
-					Logger "${FUNCNAME[0]} called by [$caller_name] finished monitoring [$pid] with exitcode [$result]." "DEBUG"
-					if [ "$WAIT_FOR_TASK_COMPLETION" == "" ]; then
-						WAIT_FOR_TASK_COMPLETION="$pid:$result"
-					else
-						WAIT_FOR_TASK_COMPLETION=";$pid:$result"
-					fi
-				fi
-			fi
-		done
 
 		Spinner
 		if [ $counting == true ]; then
@@ -643,7 +644,7 @@ function WaitForTaskCompletion {
 			if [ $soft_alert -eq 0 ] && [ $soft_max_time -ne 0 ]; then
 				Logger "Max soft execution time exceeded for task [$caller_name] with pids [$(joinString , ${pidsArray[@]})]." "WARN"
 				soft_alert=1
-				SendAlert
+				SendAlert true
 
 			fi
 			if [ $exec_time -gt $hard_max_time ] && [ $hard_max_time -ne 0 ]; then
@@ -656,12 +657,37 @@ function WaitForTaskCompletion {
 						Logger "Could not stop task with pid [$pid]." "ERROR"
 					fi
 				done
-				SendAlert
+				SendAlert true
 				errrorcount=$((errorcount+1))
 			fi
 		fi
 
+		for pid in "${pidsArray[@]}"; do
+			if kill -0 $pid > /dev/null 2>&1; then
+				# Handle uninterruptible sleep state or zombies by ommiting them from running process array (How to kill that is already dead ? :)
+				#TODO(high): have this tested on *BSD, Mac & Win
+				pidState=$(ps -p$pid -o state= 2 > /dev/null)
+				if [ "$pidState" != "D" ] && [ "$pidState" != "Z" ]; then
+					newPidsArray+=($pid)
+				fi
+			else
+				# pid is dead, get it's exit code from wait command
+				wait $pid
+				retval=$?
+				if [ $retval -ne 0 ]; then
+					errorcount=$((errorcount+1))
+					Logger "${FUNCNAME[0]} called by [$caller_name] finished monitoring [$pid] with exitcode [$retval]." "DEBUG"
+					if [ "$WAIT_FOR_TASK_COMPLETION" == "" ]; then
+						WAIT_FOR_TASK_COMPLETION="$pid:$retval"
+					else
+						WAIT_FOR_TASK_COMPLETION=";$pid:$retval"
+					fi
+				fi
+			fi
+		done
+
 		pidsArray=("${newPidsArray[@]}")
+		# Trivial wait time for bash to not eat up all CPU
 		sleep $SLEEP_TIME
 	done
 
@@ -675,6 +701,66 @@ function WaitForTaskCompletion {
 	fi
 }
 
+# Take a list of commands to run, runs them sequentially with numberOfProcesses commands simultaneously runs
+# Returns the number of non zero exit codes from commands
+function ParallelExec {
+	local numberOfProcesses="${1}" # Number of simultaneous commands to run
+	local commandsArg="${2}" # Semi-colon separated list of commands
+
+	local pid
+	local runningPids=0
+	local counter=0
+	local commandsArray
+	local pidsArray
+	local newPidsArray
+	local retval
+	local retvalAll=0
+	local pidState
+	local commandsArrayPid
+
+	IFS=';' read -r -a commandsArray <<< "$commandsArg"
+
+	Logger "Runnning ${#commandsArray[@]} commands in $numberOfProcesses simultaneous processes." "DEBUG"
+
+	while [ $counter -lt "${#commandsArray[@]}" ] || [ ${#pidsArray[@]} -gt 0 ]; do
+
+		while [ $counter -lt "${#commandsArray[@]}" ] && [ ${#pidsArray[@]} -lt $numberOfProcesses ]; do
+			Logger "Running command [${commandsArray[$counter]}]." "DEBUG"
+			eval "${commandsArray[$counter]}" &
+			pid=$!
+			pidsArray+=($pid)
+			commandsArrayPid[$pid]="${commandsArray[$counter]}"
+			counter=$((counter+1))
+		done
+
+
+		newPidsArray=()
+		for pid in "${pidsArray[@]}"; do
+			# Handle uninterruptible sleep state or zombies by ommiting them from running process array (How to kill that is already dead ? :)
+			if kill -0 $pid > /dev/null 2>&1; then
+				pidState=$(ps -p$pid -o state= 2 > /dev/null)
+				if [ "$pidState" != "D" ] && [ "$pidState" != "Z" ]; then
+					newPidsArray+=($pid)
+				fi
+			else
+				# pid is dead, get it's exit code from wait command
+				wait $pid
+				retval=$?
+				if [ $retval -ne 0 ]; then
+					Logger "Command [${commandsArrayPid[$pid]}] failed with exit code [$retval]." "ERROR"
+					retvalAll=$((retvalAll+1))
+				fi
+			fi
+		done
+		pidsArray=("${newPidsArray[@]}")
+
+		# Trivial wait time for bash to not eat up all CPU
+		sleep $SLEEP_TIME
+	done
+
+	return $retvalAll
+}
+
 function CleanUp {
 	__CheckArguments 0 $# ${FUNCNAME[0]} "$@"	#__WITH_PARANOIA_DEBUG
 
@@ -968,7 +1054,7 @@ function CheckConnectivityRemoteHost {
 
 		if [ "$REMOTE_HOST_PING" != "no" ] && [ "$REMOTE_OPERATION" != "no" ]; then
 			eval "$PING_CMD $REMOTE_HOST > /dev/null 2>&1" &
-			WaitForTaskCompletion $! 10 180 ${FUNCNAME[0]} true $KEEP_LOGGING
+			WaitForTaskCompletion $! 60 180 ${FUNCNAME[0]} true $KEEP_LOGGING
 			if [ $? != 0 ]; then
 				Logger "Cannot ping $REMOTE_HOST" "ERROR"
 				return 1
@@ -1013,12 +1099,15 @@ function __CheckArguments {
 	# Checks the number of arguments of a function and raises an error if some are missing
 
 	if [ "$_DEBUG" == "yes" ]; then
-		local number_of_arguments="${1}" # Number of arguments the tested function should have
-		local number_of_given_arguments="${2}" # Number of arguments that have been passed
-		local function_name="${3}" # Function name that called __CheckArguments
+		local numberOfArguments="${1}" # Number of arguments the tested function should have, can be a number of a range, eg 0-2 for zero to two arguments
+		local numberOfGivenArguments="${2}" # Number of arguments that have been passed
+		local functionName="${3}" # Function name that called __CheckArguments
+
+		local minArgs
+		local maxArgs
 
 		if [ "$_PARANOIA_DEBUG" == "yes" ]; then
-			Logger "Entering function [$function_name]." "DEBUG"
+			Logger "Entering function [$functionName]." "DEBUG"
 		fi
 
 		# All arguments of the function to check are passed as array in ${4} (the function call waits for $@)
@@ -1026,23 +1115,31 @@ function __CheckArguments {
 		# In order to avoid this, we need to iterate over ${4} and count
 
 		local iterate=4
-		local fetch_arguments=1
-		local arg_list=""
-		while [ $fetch_arguments -eq 1 ]; do
+		local fetchArguments=1
+		local argList=""
+		local countedArguments
+		while [ $fetchArguments -eq 1 ]; do
 			cmd='argument=${'$iterate'}'
 			eval $cmd
 			if [ "$argument" = "" ]; then
-				fetch_arguments=0
+				fetchArguments=0
 			else
-				arg_list="$arg_list [Argument $(($iterate-3)): $argument]"
+				argList="$arg_list [Argument $(($iterate-3)): $argument]"
 				iterate=$(($iterate+1))
 			fi
 		done
-		local counted_arguments=$((iterate-4))
+		countedArguments=$((iterate-4))
 
-		if [ $counted_arguments -ne $number_of_arguments ]; then
-			Logger "Function $function_name may have inconsistent number of arguments. Expected: $number_of_arguments, count: $counted_arguments, bash seen: $number_of_given_arguments. see log file." "ERROR"
-			Logger "Arguments passed: $arg_list" "ERROR"
+		if [ $(IsNumeric "$numberOfArguments") -eq 1 ]; then
+			minArgs=$numberOfArguments
+			maxArgs=$numberOfArguments
+		else
+			IFS='-' read minArgs maxArgs <<< "$numberOfArguments"
+		fi
+
+		if ! ([ $countedArguments -ge $minArgs ] && [ $countedArguments -le $maxArgs ]); then
+			Logger "Function $functionName may have inconsistent number of arguments. Expected min: $minArgs, max: $maxArgs, count: $countedArguments, bash seen: $numberOfGivenArguments. see log file." "ERROR"
+			Logger "Arguments passed: $argList" "ERROR"
 		fi
 	fi
 }
@@ -1286,7 +1383,6 @@ function InitLocalOSSettings {
 function InitRemoteOSSettings {
 	__CheckArguments 0 $# ${FUNCNAME[0]} "$@"    #__WITH_PARANOIA_DEBUG
 
-	#TODO: fix add -E when both initiator and targets don't run MacOSX and PRESERVE_EXECUTABILITY=yes
 	## MacOSX does not use the -E parameter like Linux or BSD does (-E is mapped to extended attrs instead of preserve executability)
 	if [ "$PRESERVE_EXECUTABILITY" != "no" ];then
 		if [ "$LOCAL_OS" != "MacOSX" ] && [ "$REMOTE_OS" != "MacOSX" ]; then
diff --git a/tests/run.sh b/dev/tests/run.sh
similarity index 93%
rename from tests/run.sh
rename to dev/tests/run.sh
index f3dfe3d..4448ec1 100755
--- a/tests/run.sh
+++ b/dev/tests/run.sh
@@ -1,9 +1,18 @@
 #!/usr/bin/env bash
 
+# osync shunit2 tests
+
+# modify ctime on ext4
+debugfs -w -R 'set_inode_field /tmp/foo ctime 201001010101' /dev/sda1
+echo > /proc/sys/vm/drop_caches
+
 # Test dir
 TMP="/tmp/osync_tests"
 # SSH port used for remote tests
-SSH_PORT=49999
+SSH_PORT=22
+
+INITIATOR_DIR="init"
+TARGET_DIR="targ"
 
 # Get dir the tests are stored in
 TEST_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
@@ -11,8 +20,8 @@ cd "$TEST_DIR"
 
 OSYNC_EXECUTABLE="$(dirname $TEST_DIR)//osync.sh"
 declare -A sandbox_osync
-#sandbox_osync[quickLocal]="--master=master --slave=slave"
-#sandbox_osync[quickRemote]="--master=master --slave=ssh://localhost//tmp/osync_tests/quickRemote/slave"
+sandbox_osync[quickLocal]="--initiator=$INITIATOR_DIR --target=$TARGET_DIR"
+#sandbox_osync[quickRemote]="--initiator=$INITIATOR_DIR --slave=ssh://localhost:$SSH_PORT/$TMP/$TARGET_DIR"
 #sandbox_osync[local]="conf/local.conf"
 #sandbox_osync[remote]="conf/remote.conf"
 
@@ -34,8 +43,8 @@ prepareSandbox()
     rm -rf "$TMP/$1"
     mkdir -p "$TMP/$1"
     pushd "$TMP/$1" >/dev/null
-    mkdir master
-    mkdir slave
+    mkdir "$INITIATOR_DIR"
+    mkdir "$TARGET_DIR"
     mkdir expected
     popd >/dev/null
 }
diff --git a/dev/tests/run_tests.sh b/dev/tests/run_tests.sh
new file mode 100755
index 0000000..3f88d6a
--- /dev/null
+++ b/dev/tests/run_tests.sh
@@ -0,0 +1,54 @@
+#!/usr/bin/env bash
+
+# osync test suite 2016081901
+
+DEV_DIR="/home/git/osync/dev"
+OSYNC_EXECUTABLE="n_osync.sh"
+
+INITIATOR_DIR="/opt/osync/initiator"
+TARGET_DIR="/opt/osync/target"
+OSYNC_STATE_DIR=".osync_workdir/state"
+
+function CreateReplicas () {
+	if [ -d "$INITIATOR_DIR" ]; then
+		rm -rf "$INITIATOR_DIR"
+	fi
+	mkdir -p "$INITIATOR_DIR"
+
+	if [ -d "$TARGET_DIR" ]; then
+		rm -rf "$TARGET_DIR"
+	fi
+	mkdir -p "$TARGET_DIR"
+}
+
+function oneTimeSetUp () {
+	source "$DEV_DIR/ofunctions.sh"
+
+	if grep "^IS_STABLE=YES" "$DEV_DIR/$OSYNC_EXECUTABLE" > /dev/null; then
+		IS_STABLE=yes
+	else
+		IS_STABLE=no
+		sed -i 's/^IS_STABLE=no/IS_STABLE=yes/' "$DEV_DIR/$OSYNC_EXECUTABLE"
+	fi
+}
+
+function oneTimeTearDown () {
+	if [ "$IS_STABLE" == "no" ]; then
+		sed -i 's/^IS_STABLE=yes/IS_STABLE=no/' "$DEV_DIR/$OSYNC_EXECUTABLE"
+	fi
+}
+
+function test_osync_quicksync_local () {
+	CreateReplicas
+	cd "$DEV_DIR"
+	./n_osync.sh --initiator="$INITIATOR_DIR" --target="$TARGET_DIR" > /dev/null
+	assertEquals "Return code" "0" $?
+
+	[ -d "$INITIATOR_DIR/$OSYNC_STATE_DIR" ]
+	assertEquals "Initiator state dir exists" "0" $?
+
+	[ -d "$TARGET_DIR/$OSYNC_STATE_DIR" ]
+	assertEquals "Target state dir exists" "0" $?
+}
+
+. ./shunit2/shunit2
diff --git a/tests/shunit2/shunit2 b/dev/tests/shunit2/shunit2
similarity index 100%
rename from tests/shunit2/shunit2
rename to dev/tests/shunit2/shunit2
diff --git a/tests/shunit2/shunit2_test.sh b/dev/tests/shunit2/shunit2_test.sh
similarity index 100%
rename from tests/shunit2/shunit2_test.sh
rename to dev/tests/shunit2/shunit2_test.sh
diff --git a/tests/shunit2/shunit2_test_asserts.sh b/dev/tests/shunit2/shunit2_test_asserts.sh
similarity index 100%
rename from tests/shunit2/shunit2_test_asserts.sh
rename to dev/tests/shunit2/shunit2_test_asserts.sh
diff --git a/tests/shunit2/shunit2_test_failures.sh b/dev/tests/shunit2/shunit2_test_failures.sh
similarity index 100%
rename from tests/shunit2/shunit2_test_failures.sh
rename to dev/tests/shunit2/shunit2_test_failures.sh
diff --git a/tests/shunit2/shunit2_test_helpers b/dev/tests/shunit2/shunit2_test_helpers
similarity index 100%
rename from tests/shunit2/shunit2_test_helpers
rename to dev/tests/shunit2/shunit2_test_helpers
diff --git a/tests/shunit2/shunit2_test_macros.sh b/dev/tests/shunit2/shunit2_test_macros.sh
similarity index 100%
rename from tests/shunit2/shunit2_test_macros.sh
rename to dev/tests/shunit2/shunit2_test_macros.sh
diff --git a/tests/shunit2/shunit2_test_misc.sh b/dev/tests/shunit2/shunit2_test_misc.sh
similarity index 100%
rename from tests/shunit2/shunit2_test_misc.sh
rename to dev/tests/shunit2/shunit2_test_misc.sh
diff --git a/tests/shunit2/shunit2_test_standalone.sh b/dev/tests/shunit2/shunit2_test_standalone.sh
similarity index 100%
rename from tests/shunit2/shunit2_test_standalone.sh
rename to dev/tests/shunit2/shunit2_test_standalone.sh
diff --git a/osync.sh b/osync.sh
index d3a1412..fd69046 100755
--- a/osync.sh
+++ b/osync.sh
@@ -1,20 +1,20 @@
 #!/usr/bin/env bash
 
 #TODO(critical): handle conflict prevalance, especially in sync_attrs function
-#TODO(critical): test new WaitForTaskCompletion behavior with self=true
+#TODO(critical): writelockfiles remote does not shut execution
 
 PROGRAM="osync" # Rsync based two way sync engine with fault tolerance
 AUTHOR="(C) 2013-2016 by Orsiris de Jong"
 CONTACT="http://www.netpower.fr/osync - ozy@netpower.fr"
 PROGRAM_VERSION=1.2-dev-parallel
-PROGRAM_BUILD=2016081902
+PROGRAM_BUILD=2016082201
 IS_STABLE=no
 
 
 
 #### MINIMAL-FUNCTION-SET BEGIN ####
 
-## FUNC_BUILD=2016081805
+## FUNC_BUILD=2016082204
 ## BEGIN Generic functions for osync & obackup written in 2013-2016 by Orsiris de Jong - http://www.netpower.fr - ozy@netpower.fr
 
 ## type -p does not work on platforms other than linux (bash). If if does not work, always assume output is not a zero exitcode
@@ -184,7 +184,7 @@ function KillChilds {
 		# Try to kill nicely, if not, wait 15 seconds to let Trap actions happen before killing
 	if ( [ "$self" == true ] && kill -0 $pid > /dev/null 2>&1); then
 		Logger "Sending SIGTERM to process [$pid]." "DEBUG"
-		kill -s SIGTERM "$pid"
+		kill -s TERM "$pid"
 		if [ $? != 0 ]; then
 			sleep 15
 			Logger "Sending SIGTERM to process [$pid] failed." "DEBUG"
@@ -594,29 +594,6 @@ function WaitForTaskCompletion {
 
 	while [ ${#pidsArray[@]} -gt 0 ]; do
 		newPidsArray=()
-		for pid in "${pidsArray[@]}"; do
-			if kill -0 $pid > /dev/null 2>&1; then
-				# Handle uninterruptible sleep state or zombies by ommiting them from running process array (How to kill that is already dead ? :)
-				#TODO(high): have this tested on *BSD, Mac & Win
-				pidState=$(ps -p$pid -o state= 2 > /dev/null)
-				if [ "$pidState" != "D" ] && [ "$pidState" != "Z" ]; then
-					newPidsArray+=($pid)
-				fi
-			else
-				# pid is dead, get it's exit code from wait command
-				wait $pid
-				retval=$?
-				if [ $retval -ne 0 ]; then
-					errorcount=$((errorcount+1))
-					Logger "${FUNCNAME[0]} called by [$caller_name] finished monitoring [$pid] with exitcode [$result]." "DEBUG"
-					if [ "$WAIT_FOR_TASK_COMPLETION" == "" ]; then
-						WAIT_FOR_TASK_COMPLETION="$pid:$result"
-					else
-						WAIT_FOR_TASK_COMPLETION=";$pid:$result"
-					fi
-				fi
-			fi
-		done
 
 		Spinner
 		if [ $counting == true ]; then
@@ -656,6 +633,30 @@ function WaitForTaskCompletion {
 			fi
 		fi
 
+		for pid in "${pidsArray[@]}"; do
+			if kill -0 $pid > /dev/null 2>&1; then
+				# Handle uninterruptible sleep state or zombies by ommiting them from running process array (How to kill that is already dead ? :)
+				#TODO(high): have this tested on *BSD, Mac & Win
+				pidState=$(ps -p$pid -o state= 2 > /dev/null)
+				if [ "$pidState" != "D" ] && [ "$pidState" != "Z" ]; then
+					newPidsArray+=($pid)
+				fi
+			else
+				# pid is dead, get it's exit code from wait command
+				wait $pid
+				retval=$?
+				if [ $retval -ne 0 ]; then
+					errorcount=$((errorcount+1))
+					Logger "${FUNCNAME[0]} called by [$caller_name] finished monitoring [$pid] with exitcode [$result]." "DEBUG"
+					if [ "$WAIT_FOR_TASK_COMPLETION" == "" ]; then
+						WAIT_FOR_TASK_COMPLETION="$pid:$result"
+					else
+						WAIT_FOR_TASK_COMPLETION=";$pid:$result"
+					fi
+				fi
+			fi
+		done
+
 		pidsArray=("${newPidsArray[@]}")
 		sleep $SLEEP_TIME
 	done
@@ -975,7 +976,7 @@ function CheckConnectivity3rdPartyHosts {
 			for i in $REMOTE_3RD_PARTY_HOSTS
 			do
 				eval "$PING_CMD $i > /dev/null 2>&1" &
-				WaitForTaskCompletion $! 10 360 ${FUNCNAME[0]} true $KEEP_LOGGING
+				WaitForTaskCompletion $! 180 360 ${FUNCNAME[0]} true $KEEP_LOGGING
 				if [ $? != 0 ]; then
 					Logger "Cannot ping 3rd party host $i" "NOTICE"
 				else
@@ -1310,9 +1311,7 @@ function TrapQuit {
 		exitcode=2	# Warning exit code must not force daemon mode to quit
 	else
 		UnlockReplicas
-		if [ "$RUN_AFTER_CMD_ON_ERROR" == "yes" ]; then
-			RunAfterHook
-		fi
+		RunAfterHook
 		CleanUp
 		Logger "$PROGRAM finished." "NOTICE"
 		exitcode=0
@@ -1429,15 +1428,16 @@ function CheckReplicaPaths {
 
 	local pids
 
+	# Use direct comparaison before having a portable realpath implementation
 	#INITIATOR_SYNC_DIR_CANN=$(realpath "${INITIATOR[1]}")	#TODO(verylow): investigate realpath & readlink issues on MSYS and busybox here
 	#TARGET_SYNC_DIR_CANN=$(realpath "${TARGET[1]})
 
-	#if [ "$REMOTE_OPERATION" != "yes" ]; then
-	#	if [ "$INITIATOR_SYNC_DIR_CANN" == "$TARGET_SYNC_DIR_CANN" ]; then
-	#		Logger "Master directory [${INITIATOR[1]}] cannot be the same as target directory." "CRITICAL"
-	#		exit 1
-	#	fi
-	#fi
+	if [ "$REMOTE_OPERATION" != "yes" ]; then
+		if [ "${INITIATOR[1]}" == "${TARGET[1]}" ]; then
+			Logger "Initiator and target path [${INITIATOR[1]}] cannot be the same." "CRITICAL"
+			exit 1
+		fi
+	fi
 
 	_CheckReplicaPathsLocal "${INITIATOR[1]}" &
 	pids="$!"
@@ -2746,10 +2746,10 @@ function Init {
 
 	# Do not use exit and quit traps if osync runs in monitor mode
 	if [ $sync_on_changes -eq 0 ]; then
-		trap TrapStop SIGINT SIGHUP SIGTERM SIGQUIT
+		trap TrapStop INT HUP TERM QUIT
 		trap TrapQuit EXIT
 	else
-		trap TrapQuit SIGTERM EXIT SIGHUP SIGQUIT
+		trap TrapQuit TERM EXIT HUP QUIT
 	fi
 
 	local uri
diff --git a/sync.conf b/sync.conf.example
similarity index 97%
rename from sync.conf
rename to sync.conf.example
index 87203f7..e05e780 100644
--- a/sync.conf
+++ b/sync.conf.example
@@ -2,7 +2,7 @@
 
 ###### osync - Rsync based two way sync engine with fault tolerance
 ###### (C) 2013-2016 by Orsiris de Jong (www.netpower.fr)
-###### osync v1.1x / v1.2x config file rev 2016080902
+###### osync v1.1x / v1.2x config file rev 2016081901
 
 ## ---------- GENERAL OPTIONS
 
@@ -80,7 +80,7 @@ REMOTE_3RD_PARTY_HOSTS="www.kernel.org www.google.com"
 PRESERVE_PERMISSIONS=yes
 PRESERVE_OWNER=yes
 PRESERVE_GROUP=yes
-## Does not work and will be ignored on MacOS X
+## On MACOS X, does not work and will be ignored
 PRESERVE_EXECUTABILITY=yes
 
 ## Preserve ACLS. Make sure source and target FS can manage same ACLs or you'll get loads of errors.
@@ -104,6 +104,9 @@ RSYNC_COMPRESS=yes
 SOFT_MAX_EXEC_TIME=7200
 HARD_MAX_EXEC_TIME=10600
 
+## Log a message every KEEP_LOGGING seconds just to know the task is still alive
+KEEP_LOGGING=1801
+
 ## Minimum time (in seconds) in file monitor /daemon mode between modification detection and sync task in order to let copy operations finish.
 MIN_WAIT=60
 
diff --git a/tests/conf/local.conf b/tests/conf/local.conf
deleted file mode 100755
index b52d0bf..0000000
--- a/tests/conf/local.conf
+++ /dev/null
@@ -1,143 +0,0 @@
-#!/usr/bin/env bash
-
-###### Osync - Rsync based two way sync engine with fault tolerance
-###### (L) 2013-2014 by Orsiris "Ozy" de Jong (www.netpower.fr)
-###### Config file rev 2611201401
-
-## ---------- GENERAL OPTIONS
-
-## Sync job identification
-SYNC_ID="sync_test"
-
-## Directories to synchronize. Master must be on the system Osync runs on. Slave can be either a local directory, or a remote one.
-MASTER_SYNC_DIR="master"
-SLAVE_SYNC_DIR="slave"
-#SLAVE_SYNC_DIR="ssh://backupuser@yourhost.old:22//home/git/osync/dir2"
-## If slave replica is a remote directory, you must specify a RSA key (please use full path). Please see documentation for further information.
-#SSH_RSA_PRIVATE_KEY="/home/backupuser/.ssh/id_rsa"
-
-## Create sync directories if they do not exist
-CREATE_DIRS=no
-
-## Log file location. Leaving this empty will create a logfile at /var/log/osync_version_SYNC_ID.log (or current directory if /var/log doesn't exist)
-LOGFILE=""
-
-
-## List of directories to exclude from sync on both sides (rsync patterns, wildcards work).
-## Paths are relative to sync dirs. List elements are separated by a semicolon.
-RSYNC_EXCLUDE_PATTERN=""
-#RSYNC_EXCLUDE_PATTERN="tmp;archives"
-
-## File that contains the list of directories or files to exclude from sync on both sides. Leave this empty if you don't want to use an exclusion file.
-## This file has to be in the same directory as the config file
-## Paths are relative to sync dirs. One element per line.
-RSYNC_EXCLUDE_FROM=""
-#RSYNC_EXCLUDE_FROM="exclude.list"
-
-## List elements separator char.  You may set an alternative separator char for your directories lists above.
-PATH_SEPARATOR_CHAR=";"
-
-## Generate an alert if master or slave replicas have less free space than given value in KB.
-MINIMUM_SPACE=10240
-
-## Bandwidth limit Kbytes / second. Leave 0 to disable limitation
-BANDWIDTH=0
-
-## If enabled, synchronization on remote system will be processed as superuser. See documentation for /etc/sudoers file configuration.
-SUDO_EXEC=no
-## Paranoia option. Don't change this unless you read the documentation.
-RSYNC_EXECUTABLE=rsync
-
-## ---------- REMOTE SYNC OPTIONS
-
-## ssh compression should be used unless your remote connection is good enough (LAN)
-SSH_COMPRESSION=yes
-
-## Check for connectivity to remote host before launching remote sync task. Be sure the hosts responds to ping. Failing to ping will stop sync.
-REMOTE_HOST_PING=no
-
-## Check for internet access by pinging one or more 3rd party hosts before remote sync task. Leave empty if you don't want this check to be be performed. Failing to ping will stop sync.
-## If you use this function, you should set more than one 3rd party host, and be sure you can ping them.
-## Be aware some DNS like opendns redirect false hostnames. Also, this adds an extra execution time of a bit less than a minute.
-REMOTE_3RD_PARTY_HOSTS=""
-
-## Remote rsync executable path. Leave this empty in most cases
-RSYNC_REMOTE_PATH=""
-
-## ---------- MISC OPTIONS
-
-## Preserve ACLS. Make sure source and target FS can manage same ACLs or you'll get loads of errors.
-PRESERVE_ACL=no
-## Preserve Xattr. Make sure source and target FS can manage same Xattrs or you'll get loads of errors.
-PRESERVE_XATTR=no
-## Transforms symlinks into referent files/dirs
-COPY_SYMLINKS=no
-## Treat symlinked dirs	as dirs. CAUTION: This also follows symlinks outside of the replica root.
-KEEP_DIRLINKS=no
-## Preserve hard links. Make sure source and target FS can manage hard links or you will lose them.
-PRESERVE_HARDLINKS=no
-
-## Let RSYNC compress file transfers. Do not use this if both master and slave replicas are on local system. Also,  do not use this if you already enabled SSH compression.
-RSYNC_COMPRESS=yes
-
-## Maximum execution time (in seconds) for sync process. Soft exec time only generates a warning. Hard exec time will generate a warning and stop sync process.
-SOFT_MAX_EXEC_TIME=7200
-HARD_MAX_EXEC_TIME=10600
-
-## Minimum time (in seconds) in file monitor /daemon mode between modification detection and sync task in order to let copy operations finish.
-MIN_WAIT=60
-
-## ---------- BACKUP AND DELETION OPTIONS
-
-## Enabling this option will keep a backup of a file on the target replica if it gets updated from the source replica. Backups will be made to .osync_workdir/backups
-CONFLICT_BACKUP=yes
-## Keep multiple backup versions of the same file. Warning, This can be very space consuming.
-CONFLICT_BACKUP_MULTIPLE=no
-## Osync will clean backup files after a given number of days. Setting this to 0 will disable cleaning and keep backups forever. Warning: This can be very space consuming.
-CONFLICT_BACKUP_DAYS=30
-## If the same file exists on both replicas, newer version will be synced. However, if both files have the same timestamp but differ, CONFILCT_PREVALANCE sets winner replica.
-CONFLICT_PREVALANCE=master
-
-## On deletion propagation to the target replica, a backup of the deleted files can be kept. Deletions will be kept in .osync_workdir/deleted
-SOFT_DELETE=yes
-## Osync will clean deleted files after a given number of days. Setting this to 0 will disable cleaning and keep deleted files forever. Warning: This can be very space consuming.
-SOFT_DELETE_DAYS=30
-
-## ---------- RESUME OPTIONS
-
-## Try to resume an aborted sync task
-RESUME_SYNC=yes
-## Number maximum resume tries before initiating a fresh sync.
-RESUME_TRY=2
-## When a pidlock exists on slave replica that does not correspond to master's sync-id, force pidlock removal. Be careful with this option if you have multiple masters.
-FORCE_STRANGER_LOCK_RESUME=no
-
-## Keep partial uploads that can be resumed on next run, experimental feature
-PARTIAL=no
-
-## ---------- ALERT OPTIONS
-
-## List of alert mails separated by spaces
-DESTINATION_MAILS="your@alert.tld"
-
-## Windows (MSYS environment) only mail options (used with sendemail.exe from Brandon Zehm)
-SENDER_MAIL="alert@your.system.tld"
-SMTP_SERVER=smtp.your.isp.tld
-SMTP_USER=
-SMTP_PASSWORD=
-
-## ---------- EXECUTION HOOKS
-
-## Commands can will be run before and / or after sync process (remote execution will only happen if REMOTE_SYNC is set).
-LOCAL_RUN_BEFORE_CMD=""
-LOCAL_RUN_AFTER_CMD=""
-
-REMOTE_RUN_BEFORE_CMD=""
-REMOTE_RUN_AFTER_CMD=""
-
-## Max execution time of commands before they get force killed. Leave 0 if you don't wan't this to happen. Time is specified in seconds.
-MAX_EXEC_TIME_PER_CMD_BEFORE=0
-MAX_EXEC_TIME_PER_CMD_AFTER=0
-
-## Stops Osync execution if one of the above commands fail
-STOP_ON_CMD_ERROR=yes
diff --git a/tests/conf/remote.conf b/tests/conf/remote.conf
deleted file mode 100755
index 475e0c9..0000000
--- a/tests/conf/remote.conf
+++ /dev/null
@@ -1,143 +0,0 @@
-#!/usr/bin/env bash
-
-###### Osync - Rsync based two way sync engine with fault tolerance
-###### (L) 2013-2014 by Orsiris "Ozy" de Jong (www.netpower.fr)
-###### Config file rev 2611201401
-
-## ---------- GENERAL OPTIONS
-
-## Sync job identification
-SYNC_ID="sync_test"
-
-## Directories to synchronize. Master must be on the system Osync runs on. Slave can be either a local directory, or a remote one.
-MASTER_SYNC_DIR="master"
-SLAVE_SYNC_DIR="ssh://localhost//tmp/osync_tests/remote/slave"
-#SLAVE_SYNC_DIR="ssh://backupuser@yourhost.old:22//home/git/osync/dir2"
-## If slave replica is a remote directory, you must specify a RSA key (please use full path). Please see documentation for further information.
-#SSH_RSA_PRIVATE_KEY="/home/backupuser/.ssh/id_rsa"
-
-## Create sync directories if they do not exist
-CREATE_DIRS=yes
-
-## Log file location. Leaving this empty will create a logfile at /var/log/osync_version_SYNC_ID.log (or current directory if /var/log doesn't exist)
-LOGFILE=""
-
-
-## List of directories to exclude from sync on both sides (rsync patterns, wildcards work).
-## Paths are relative to sync dirs. List elements are separated by a semicolon.
-RSYNC_EXCLUDE_PATTERN=""
-#RSYNC_EXCLUDE_PATTERN="tmp;archives"
-
-## File that contains the list of directories or files to exclude from sync on both sides. Leave this empty if you don't want to use an exclusion file.
-## This file has to be in the same directory as the config file
-## Paths are relative to sync dirs. One element per line.
-RSYNC_EXCLUDE_FROM=""
-#RSYNC_EXCLUDE_FROM="exclude.list"
-
-## List elements separator char.  You may set an alternative separator char for your directories lists above.
-PATH_SEPARATOR_CHAR=";"
-
-## Generate an alert if master or slave replicas have less free space than given value in KB.
-MINIMUM_SPACE=10240
-
-## Bandwidth limit Kbytes / second. Leave 0 to disable limitation
-BANDWIDTH=0
-
-## If enabled, synchronization on remote system will be processed as superuser. See documentation for /etc/sudoers file configuration.
-SUDO_EXEC=no
-## Paranoia option. Don't change this unless you read the documentation.
-RSYNC_EXECUTABLE=rsync
-
-## ---------- REMOTE SYNC OPTIONS
-
-## ssh compression should be used unless your remote connection is good enough (LAN)
-SSH_COMPRESSION=yes
-
-## Check for connectivity to remote host before launching remote sync task. Be sure the hosts responds to ping. Failing to ping will stop sync.
-REMOTE_HOST_PING=no
-
-## Check for internet access by pinging one or more 3rd party hosts before remote sync task. Leave empty if you don't want this check to be be performed. Failing to ping will stop sync.
-## If you use this function, you should set more than one 3rd party host, and be sure you can ping them.
-## Be aware some DNS like opendns redirect false hostnames. Also, this adds an extra execution time of a bit less than a minute.
-REMOTE_3RD_PARTY_HOSTS=""
-
-## Remote rsync executable path. Leave this empty in most cases
-RSYNC_REMOTE_PATH=""
-
-## ---------- MISC OPTIONS
-
-## Preserve ACLS. Make sure source and target FS can manage same ACLs or you'll get loads of errors.
-PRESERVE_ACL=no
-## Preserve Xattr. Make sure source and target FS can manage same Xattrs or you'll get loads of errors.
-PRESERVE_XATTR=no
-## Transforms symlinks into referent files/dirs
-COPY_SYMLINKS=no
-## Treat symlinked dirs	as dirs. CAUTION: This also follows symlinks outside of the replica root.
-KEEP_DIRLINKS=no
-## Preserve hard links. Make sure source and target FS can manage hard links or you will lose them.
-PRESERVE_HARDLINKS=no
-
-## Let RSYNC compress file transfers. Do not use this if both master and slave replicas are on local system. Also,  do not use this if you already enabled SSH compression.
-RSYNC_COMPRESS=yes
-
-## Maximum execution time (in seconds) for sync process. Soft exec time only generates a warning. Hard exec time will generate a warning and stop sync process.
-SOFT_MAX_EXEC_TIME=7200
-HARD_MAX_EXEC_TIME=10600
-
-## Minimum time (in seconds) in file monitor /daemon mode between modification detection and sync task in order to let copy operations finish.
-MIN_WAIT=60
-
-## ---------- BACKUP AND DELETION OPTIONS
-
-## Enabling this option will keep a backup of a file on the target replica if it gets updated from the source replica. Backups will be made to .osync_workdir/backups
-CONFLICT_BACKUP=yes
-## Keep multiple backup versions of the same file. Warning, This can be very space consuming.
-CONFLICT_BACKUP_MULTIPLE=no
-## Osync will clean backup files after a given number of days. Setting this to 0 will disable cleaning and keep backups forever. Warning: This can be very space consuming.
-CONFLICT_BACKUP_DAYS=30
-## If the same file exists on both replicas, newer version will be synced. However, if both files have the same timestamp but differ, CONFILCT_PREVALANCE sets winner replica.
-CONFLICT_PREVALANCE=master
-
-## On deletion propagation to the target replica, a backup of the deleted files can be kept. Deletions will be kept in .osync_workdir/deleted
-SOFT_DELETE=yes
-## Osync will clean deleted files after a given number of days. Setting this to 0 will disable cleaning and keep deleted files forever. Warning: This can be very space consuming.
-SOFT_DELETE_DAYS=30
-
-## ---------- RESUME OPTIONS
-
-## Try to resume an aborted sync task
-RESUME_SYNC=yes
-## Number maximum resume tries before initiating a fresh sync.
-RESUME_TRY=2
-## When a pidlock exists on slave replica that does not correspond to master's sync-id, force pidlock removal. Be careful with this option if you have multiple masters.
-FORCE_STRANGER_LOCK_RESUME=no
-
-## Keep partial uploads that can be resumed on next run, experimental feature
-PARTIAL=no
-
-## ---------- ALERT OPTIONS
-
-## List of alert mails separated by spaces
-DESTINATION_MAILS="your@alert.tld"
-
-## Windows (MSYS environment) only mail options (used with sendemail.exe from Brandon Zehm)
-SENDER_MAIL="alert@your.system.tld"
-SMTP_SERVER=smtp.your.isp.tld
-SMTP_USER=
-SMTP_PASSWORD=
-
-## ---------- EXECUTION HOOKS
-
-## Commands can will be run before and / or after sync process (remote execution will only happen if REMOTE_SYNC is set).
-LOCAL_RUN_BEFORE_CMD=""
-LOCAL_RUN_AFTER_CMD=""
-
-REMOTE_RUN_BEFORE_CMD=""
-REMOTE_RUN_AFTER_CMD=""
-
-## Max execution time of commands before they get force killed. Leave 0 if you don't wan't this to happen. Time is specified in seconds.
-MAX_EXEC_TIME_PER_CMD_BEFORE=0
-MAX_EXEC_TIME_PER_CMD_AFTER=0
-
-## Stops Osync execution if one of the above commands fail
-STOP_ON_CMD_ERROR=yes