#!/bin/sh
# Lanzador de maquina virtual con Qemu
# Version 0:2026.05.05
# Copyright (GNU GPL) Narcis Garcia

# Program development at projectes_publics/matromu/matromu

# Depends on other software: qemu/kvm bc netstat/net-tools file

# Com a primer paràmetre cal especificar la ruta del fitxer .iso o imatge de disc dur d'arrencada.
# Automàticament s'utilitzarà/generarà un fitxer .matromu a la mateixa ubicació.
# En comptes d'això, també es pot especificar directament la ruta del fitxer .matromu
BootMedia="$1"

# PENDENT:
#	- Quan (normalment per estar repetint la MAC) es crea una NIC-TAP (per a unir a un pont) amb un nom repetit, es desconfigura la què ja hi havia.
#	  Caldria advertir l'usuari en cas de duplicitat de MAC
#	  Caldria comprovar els noms de NIC/TAP existents per a no repetir (afegir algun dígit més)
#	- Profile parameter "re-vnc" to reconnect automatically when VNCd connection is lost and VM remains listening VNC port.
#	- The "vlan" parameter to -net was deprecated in QEMU 2.9.0 and removed in a subsequent release
#	- qemu-system -D logfile : Output log in logfile instead of to stderr
#	- Comprobar que virtio-scsi no da incompatibilidades con sistemas-invitado antiguos (MS-DOS, Windows 9x, Debian 2, etc.)
#	- !! PREVENIR que 2 instancias de Qemu usen una misma imagen o dispositivo en r/w !! (analizar procesos, lsof, etc.)
#	- Paràmetre de VM: StopCommand="sshpass -p **** ssh user@guest.lan -p 22 -t -o StrictHostKeyChecking=no shutdown -h -P now"
#	  A més a més, cal explorar les possibilitats de qemu-guest-agent
#	- Paràmetre de VM: StopTimeoutSec=20
#	- Visualització rdesktop:ip:port per RDP.
#	- Comprovar si realment Qemu no impedeix l'accés R/W simultani a 2 VM.
#	  Si no és així, coordinar el bloqueig mitjançant /tmp/matromu/files.lock consistent en una taula de PID+espai+RutaFitxer
#	- Alerta sota Debian 9:
#		Image format was not specified for 'bell1.img' and probing guessed raw.
#		Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
#		Specify the 'raw' format explicitly to remove the restrictions.
#	- Si ja hi ha un pont (bridge) en ús per altres VM, especificant un pont diferent no s'aconsegueix la separació desitjada, i la NIC va al pont existent.
#	- ATENCIÓ! Paràmetres com -FullColor depenen de xvnc4viewer i no estan suportats per xtightvncviewer
#	- Si una imatge de disc és inferior a 3MiB, aleshores passar-la amb: -fda disc.img -boot a
#	- Admetre paràmetre --sampleprofile per a què matromus l'invoqui per la creació d'un child.
#	- Fer que el "index" de les unitats de disc s'ordeni sempre: Primer floppys, després discs durs, i per últim CD-ROMs. Alguns sistemes antics no suporten un canvi d'ordre després d'instal·lar.
#	- Si una imatge de disc fa menys de 3MiB, assumir que és floppy.
#	- No sembla reconnectar per VNC quan l'usuari ha tallat i tornat a cridar la mateixa VM.
#	- La sintaxi NetChannel1="model/mac/bridge" hauria de preveure les paraules "auto-wan", "auto-lan" i "auto-any" com a bridge:
#		auto-wan: cercar un pont existent que tingui la sortida predeterminada a internet. Si no hi és, crear-lo i moure-hi la interfície de sortida actual.
#		auto-lan: cercar un pont existent que NO tingui la sortida pred.internet. Si no n'hi ha, crear-lo com a pont independent.
#		auto-any: cercar qualsevol pont existent (preferentment wan). Si no n'hi ha, crear-lo i moure-hi la interfície de sortida WAN actual.
#	- Que la primera execució de Matromu controli la virtualització de forma síncrona; els VNCs han de ser els secundaris (assíncrons)
#	  Tant per VNCd com VNCi llançar un procés paral·lel abans de Qemu:
#		matromu --vncd $host:$port &
#		matromu --vnci $host:$port &
#	- Esquema de temporals (a /run/shm o /tmp):
#		/tmp/matromu/		[a=rwX]
#		/tmp/matromu/$ProfileID/	[a=rwX]
#		/tmp/matromu/$ProfileID/profilefile.txt		[ug=rw,o=r] [ruta al fitxer-perfil]
#		/tmp/matromu/$ProfileID/singlerun.lock		[ug=rw,o=r] [present en cas d'exclusivitat, i contenint el $RunID de qui l'ha marcat]
#		/tmp/matromu/$ProfileID/$RunID/		[u=rwX,g=rX,o=] [$RunID = PID de Matromu]
#		/tmp/matromu/$ProfileID/$RunID/matromu.conf
#		/tmp/matromu/$ProfileID/$RunID/result.txt
#	- Resumir Architecture+Chipset+ProfileCPU en un sol paràmetre HardwareProfile="i386/pc-0.13/core2duo"
#	- Quan es mata matromu amb tun/tap connectat, després no es pot iniciar el mateix perfil:
#	  could not configure /dev/net/tun (tap7CB5): Device or resource busy
#	  -> Caldria detectar que era l'anterior, i aleshores desconfigurar-lo abans de re-configurar-lo.
#	- Problema: si per exemple s'especifica /dev/sdd i no existeix, proposa crear-ho com a imatge de disc.
#	- Configuracions generals de Matromu (es llegeixin tots):
#		/etc/matromu/defaults.conf
#		/etc/matromu/local.conf
#		~/.matromu/user.conf
#	- Carregar/desar el paràmetre de configuració «Only1Machine» que evita 2 execucions de Qemu
#	- Fer configurable on es creen els fitxers de control (.lock .log), al mateix directori o bé en una ruta específica.
#	- Fer configurable que NO es crein fitxers de perfil .matromu (aleshores que sempre s'utilitzin paràmetres predeterminats)
#	- Fer configurable una plantilla de paràmetres predeterminats pels perfils:
#		/etc/matromu/defaults.matromu
#		/etc/matromu/local.matromu
#		~/.matromu/user.matromu
#	- Anotar la versió de Qemu i altres utilitats a la bitàcola.
#	- Qemu 0.12.5 (venia amb Ubuntu 10.10) no admet paràmetre "cache" pels discs
#	- Implementar una nova variable de perfil (VncPassword) per restringir sota contrasenya l'accés VNC.
#	- Detectar si la NIC WAN del HN ja és un pont (bridge),  i en cas que no crear-lo igual com es crea una NIC virtual en forma de pont.
#	  if [ -d /sys/class/net/eth0/bridge/. ]; then
#		ÉS UN PONT
#	  else
#		Crear lanbr0/1/2/3.. amb dades de xarxa compatibles amb la NIC WAN
#	  fi
#	  Lidiar amb NetworkManager per a què s'empassi un nou pont. nmcli és la utilitat. Veure (man nm-settings i man nmcli-examples) pels paràmetres.
#	- Que es posin a prova els permisos (xarxa directa i dispositiu real) abans d'intentar sudo/gksudo/pkexec:
#	  Primer es provi d'executar qemu com a l'usuari present, i si retorna error de permisos tornar-hi amb sudo/gksudo
#	  sense errors aparents.
#	- En reconnectar a una màquina per VNCd, sobreescriu la bitàcola; l'hauria d'aprofitar.
#	- Utilitzar tots els paràmetres proporcionats $1 $2 $3... com a discos secundari, terciari, etc. a incloure a la màquina.
#	- Explorar la utilitat virsh del paquet libvirt-bin
#	- Utilitzar el paràmetre -pidfile per seguir millor el procés Qemu.
#	- Idiomes ca/es/en
#	- Si ja estava engegat i nomes va amb VNCi, preguntar per matar-lo.
#	- Documentar a la bitàcola totes les accions, i resultats.
#	- Utilitzar blkid per analitzar els dispositius de bloc a les línies 600+
#	  on ara s'utilitza l'anàlisi $UnitatsOptiques
#	- Generar ~/.matromu.conf pels valors predeterminats, els quals l'usuari es pugui
#	  personalitzar.
#	- Completar on diu «En aquest punt» (diversos llocs)
#	- Permetre (i predeterminar) una variable %RAM% pel HandyName i així ensenyar els MiB
#	- Impedir execucions paral·leles d'una VM quan es criden unes sense persistència i altres amb.
#	- Comprovar que qemu està instal·lat
#	- Si no hi ha vncviewer, que sigui l'usuari que es preocupi d'instal·lar-lo.
#	- Que no es perdin els missatges reportats dins de processos «screen»
#	- Variable UsbDevices per símplement enumerar els identificadors 0123:0123 a connectar.
#	- Aconseguir registrar MIME per proporcionar menú contextual en entorn gràfic,
#	  i així poder ja empaquetar matromu.deb i anunciar-lo a GiLUG. Però haurà de ser bilingüe.
#	  Veure desktop-file-install i update-desktop-database
#	- Comprovar la detecció que fa GetQemuBin() amb $(uname -m) en un sistema PowerPC i PowerPC64.
#	- Condicionar el -enable-kvm també a si estem emulant la mateixa plataforma que el host.
#	- Utilitzar -pidfile per controlar el número de procés que després es pugui matar.
#	- Utilitzar preferentment screen per bifurcar, i així permetre el canvi a monitor/consola de Qemu encara que s'executi en CLI (servidor/matromus)
#	  Provar si el paràmetre -daemonize de Qemu ajuda en algun sentit.
#	  https://qemu.weilnetz.de/qemu-doc.html#mux_005fkeys
#	  (intentar utilitzar igualment DaemonizeCommand() per controlar PIDs i aconseguir el mateix control amb SystemD)
#	- Experimentar amb -writeconfig i -readconfig, per si fos útil com a log o per personalitzacions.
#	- Afegir variable ContrasenyaVisual per establir-la en VNCd: qemu-kvm [...] -vnc :1,*****
#	- Hi ha problemes en establir més d'una NIC ethernet. Probablement calgui
#	  utilitzar el paràmetre «vlan» (oju que Qemu 3.1 es queixa amb "-net nic,vlan=...")
#		qemu-system-x86_64: Invalid parameter 'vlan'
#	- Estem fent servir SuperuserOnly per la xarxa (tunctl), però no ens hauria de caldre executar Qemu com a root.
#	  D'altra banda, assajar que tunctl cal executar-lo per un usuari amb "CAP_NET_ADMIN capability", de manera
#	  que apart de "root" ho poden fer altres usuaris autoritzats (si no és el cas es pot llançar un avís)
#	- Afegir paràmetre RunAs per a fer l'execució com a un altre usuari (també root). Útil per accedir a unitats físiques o xarxa completa.
#	- Utilitzar paràmetres sobre x509 per xifrar la comunicació via TLS
#	- L'ús de PrefixSudo pot ser inconvenient en entorns CLI, ja que s'utilitza de forma assíncrona (screen/start-stop-daemon)
#	- Canviar "-k es" pel que correspongui del teclat configurat a nivell d'usuari o sistema.
#	  "you must use the -k parameter to set the keyboard layout if you are not using en-us"
#	- Cal resoldre quan va amb VNCd pel «primer port lliure», l'usuari tanca la finestra i torna a intentar obrir;
#	  el primer port lliure serà un altre i fracasarà la reconnexió.
#	- Admetre una comanda a PreviousErrorAbortsMessage="$(comanda)"
#	- Paràmetre per generar un perfil.matromu d'exemple
#	- Hi ha algun error que resulta(0). Per exemple, en especificar -vga tcx (caldria assumir error si ha finalitzat en menys de 5 segons i s'intercepta la cadena "Error:")
#	- Que el paràmetre extra -no-frame s'apliqui en el possible al client VNC.
#	- .newmac.conf hauria de ser comú per tot el sistema, i escrivible per qualsevol usuari amb permisos TUN/TAP
#	- En connectar via VNC, comprovar amb nc que el port està obert; si no és així: donar un missatge del problema (VM encara no iniciada/etc.)
#	- PreviousCommand i PosteriorCommand s'han d'executar com a root en cas que SuperuserOnly=1
#	- PreviousCommand se debe ejecutar como llamada global ante la ejecución de Qemu. Esto para hacer posible el establecimiento de variables como "export QEMU_PA_SAMPLES=4096 QEMU_AUDIO_DRV=pa"
#	- Funcionalitat (API) de connexió remota (vncviewer), que comprovi la disponibilitat del host (ping) i el port (nc) i es queixi a l'estil de Joan&RosaMaria.
#	  Afegir també opció de WakeOnLan per qual el host està aturat. Que reconegui la xarxa local per a què un portàtil no intenti tot això en WAN.
#	- Para establecer la memoria gráfica, hay que declarar el dispositivo como: -device qxl-vga,vram_size_mb=256
#	- Parece que no se comprueba la existencia del Media2 (al menos para ficheros .iso)
#	- Implementar reemplaçament de -netdev per -nic a partir de Qemu 3
#	- Reemplazar el uso del obsoleto «brctl» por «ip/bridge» cuando esté disponible.
#		Crear puente: ip link add name bridge_name type bridge
#		Levantar puente: ip link set bridge_name up
#		Activar NIC (requerido para puentearla): ip link set eth0 up
#		Agregar NIC a puente: ip link set eth0 master bridge_name
#		Listar NICs con su puente asociado: bridge link
#		Sacar NIC de puente: ip link set eth0 nomaster
#		Desmembrar y eliminar puente: ip link delete bridge_name type bridge


# NOTES:
#	Observar https://qemu-project.gitlab.io/qemu/about/removed-features.html


ProgramExecutablePath=/usr/bin/matromu


##### PROGRAM FUNCTIONS from @-funcions 0:2018.10.24 #####

WhereProgram ()
# Syntax as a function: $(WhereProgram $Command)
# Description: Returns existing program filepath from specified command, or internal shell program or function
# Notes:
#	- Similar to the debianutils' "which"
# Depends on functions: (none)
# Depends on software packages: (none)
{
	local Program="$1"
	local Value=''
	
	Value="$(command -v "$Program" 2>/dev/null)"
	if [ "$Value" != "" ] ; then
		# Some scenarios "command" returns directories as executables.
		if [ -d "$Value" ] && [ "$(printf '%s' "$Value" | tr '/' ' ')" != "$Value"  ] ; then Value='' ; fi
	fi
	if [ "$Value" != "" ] ; then
		printf '%s\n' "$Value"
	fi
}

Is_Executable ()
# Syntax as a function: Is_Executable $Command
# Description: Returns (exitcode 0) TRUE if specified command's argument is an existing executable file, internal program or function; or FALSE otherwise.
# Use example (without brackets []):
#	if Is_Executable nano ; then echo "Program exists." ; fi
# Depends on functions: (none)
# Depends on software packages: (none)
{
	local Program="$1"
	local TrueCode=254  # 254=FALSE
	local TestValue=''
	
	TestValue="$(command -v "$Program" 2>/dev/null)"
	IsEmptyString () { WordsNr () { printf '%s' $#; }; return $(WordsNr $*); }
	if ! IsEmptyString "$TestValue" ; then
		# Some scenarios "command" returns directories as executables.
		if [ ! -d "$TestValue" ] || [ "$(printf '%s' "$TestValue" | tr '/' ' ')" = "$TestValue"  ] ; then
			TrueCode=0
		fi
	fi
	return $TrueCode
}

Is_IntegerNr ()
# Syntax as a function: Is_IntegerNr $Valor
# Description: Returns (exitcode 0) TRUE if specified value is an integer number, or FALSE otherwise. (IsNumeric/EsNumerico)
# Use example (without brackets []):
#	if Is_IntegerNr $Respuesta ; then echo "Correcto." ; fi
# Use example verifying also there is only 1 word:
#	if Is_IntegerNr "$Respuesta" ; then echo "Correcto." ; fi
# Notes:
#	- Only first parameter is evaluated. No matter next parameters contain.
# Depends on functions: (none)
# Depends on software packages: (none)
{
	local TestValue="$1"
	TestValue="$(expr "$TestValue" : '[ ]*\(.*[^ ]\)[ ]*$')"	# Trim spaces
	if [ "$TestValue" = "" ] ; then TestValue='.' ; fi
	[ "$TestValue" -eq "$TestValue" ] > /dev/null 2>&1
	return $?
}

Dirname ()
# Independent version of GNU dirname
# Useful for Busybox and other minimalistic environments
# Notes:
#	- Only allows 1 path specified
#	- Does not allow any option (such as -z or --version)
# Depends on functions: (none)
# Depends on other software: (none)
{
	local Path="$1"
	local NrElement=0
	local TotalElements=0
	local CurrentElement=''
	local PreviousElement=''
	local Value=''
	
	if [ "$Path" != "" ] ; then
		if [ "$Path" != "/" ] ; then
			IFS="/" ; for CurrentElement in $Path ; do
				NrElement=$(($NrElement + 1))
				if [ $NrElement -gt 1 ] ; then
					if [ $NrElement -gt 2 ] ; then
						if [ "$Value" != "/" ] ; then Value="${Value}/" ; fi
					fi
					Value="${Value}${PreviousElement}"
				else
					if [ "$CurrentElement" = "" ] ; then Value="/" ; fi
				fi
				PreviousElement="$CurrentElement"
			done
			unset IFS
			if [ $NrElement -eq 1 ] && [ "$Value" = "" ] ; then Value="." ; fi
		else
			Value="/"
		fi
	else
		Value="."
	fi
	if [ "$Value" != "" ] ; then printf '%s\n' "$Value" ; fi
}

ReadlinkF ()
# Old compatibility replacement for modern "readlink -f"
# "canonicalize by following every symlink in every component of the given name recursively; all but the last component must exist"
# Depends on functions: Dirname
# Depends on other software: grep, sed
{
	local Element="$1"
	local PreviousDir=''
	local CurrentElement=''
	local CurrentPath=''
	local TmpElement=''
	local BaseElement=''
	local ReadlinkResult=0
	local LastPath=''
	local CurStep=''
	local Value=''

	if [ "$Element" != "" ] ; then
		PreviousDir="$(pwd)"
		CurrentRelElement="$Element"
		if [ "$(ls "$CurrentRelElement" 2>/dev/null)" = "" ] && [ -d "$(Dirname "$CurrentRelElement")" ] ; then
			# Same as "readlink -f" behaviour: If element doesn't exist (but path yes), return as if existed.
			cd "$(Dirname "$CurrentRelElement")"
			Value="$(pwd | sed -e 's|/$||g')"
			Value="${Value}/$(printf '%s\n' "$CurrentRelElement" | tr -s '/' '\n' | tail -n 1)"
		fi
		while [ "$(ls "$CurrentRelElement" 2>/dev/null)" != "" ] ; do	# A broken link is not detected with -e
			if [ -d "$(Dirname "$CurrentRelElement")" ] ; then
				cd "$(Dirname "$CurrentRelElement")"
				CurrentPath="$(pwd)"
			else
				CurrentPath="$(Dirname "$CurrentRelElement")"
				if [ "$(printf '%s\n' "$CurrentPath" | grep -e '^/')" = "" ] ; then
					# Relative path
					LastPath="$(pwd)"
					IFS="/" ; for CurStep in $CurrentPath ; do unset IFS
						if [ "$CurStep" = ".." ] ; then
							LastPath="$(Dirname "$LastPath")"
						else
							if [ "$CurStep" = "." ] ; then
								LastPath="$LastPath"
							else
								if [ "$CurStep" = "" ] ; then
									LastPath="$LastPath"
								else
									LastPath="$(printf '%s\n' "$LastPath" | sed -e 's|/$||g')/${CurStep}"
								fi
							fi
						fi
					done
					CurrentPath="$LastPath"
				fi
				CurrentPath="$(printf '%s\n' "$CurrentPath" | sed -e 's|/$||g')"
			fi
			BaseElement="$(printf '%s\n' "$CurrentRelElement" | tr -s '/' '\n' | tail -n 1)"	# Problems with a path begun with "-" in old GNU basename versions
			if [ "$CurrentPath" = "/" ] ; then CurrentPath="" ; fi
			Value="${CurrentPath}/${BaseElement}"
			NextRelElement="$(readlink "$BaseElement" 2>/dev/null)"
			ReadlinkResult=$?
			if [ "$NextRelElement" != "" ] ; then
				CurrentRelElement="$NextRelElement"
			else
				if [ $ReadlinkResult -eq 0 ] || [ $ReadlinkResult -eq 1 ] ; then
					# Old readlink (such as v1.13.3 in Potato debianutils) returns exitcode 1 if element is not a link.
					CurrentRelElement=""
				else
					NextRelElement="$(stat "$BaseElement" | grep -ie 'File:' | cut -f 4 -d '"')"	#'
					if [ "$NextRelElement" != "" ] ; then
						CurrentRelElement="$NextRelElement"
					else
						CurrentRelElement="$(stat "$BaseElement" | grep -ie 'File:' | cut -f 4 -d '"')"	#'
					fi
				fi
			fi
			if [ "$CurrentRelElement" != "" ] && [ "$(ls "$CurrentRelElement" 2>/dev/null)" = "" ] ; then
				# Broken link
				BaseElement="$(printf '%s\n' "$CurrentRelElement" | tr -s '/' '\n' | tail -n 1)"	# Problems with a path begun with "-" in old GNU basename versions
				CurrentPath="$(Dirname "$CurrentRelElement")"
				if [ "$(printf '%s\n' "$CurrentPath" | grep -e '^/')" = "" ] ; then
					# Relative path
					LastPath="$(pwd)"
					IFS="/" ; for CurStep in $CurrentPath ; do unset IFS
						if [ "$CurStep" = ".." ] ; then
							LastPath="$(Dirname "$LastPath")"
						else
							if [ "$CurStep" = "." ] ; then
								LastPath="$LastPath"
							else
								if [ "$CurStep" = "" ] ; then
									LastPath="$LastPath"
								else
									LastPath="$(printf '%s\n' "$LastPath" | sed -e 's|/$||g')/${CurStep}"
								fi
							fi
						fi
					done
					CurrentPath="$LastPath"
				fi
				CurrentPath="$(printf '%s\n' "$CurrentPath" | sed -e 's|/$||g')"
				Value="${CurrentPath}/${BaseElement}"
			fi
		done
		cd "$PreviousDir"
		if [ "$Value" != "" ] ; then printf '%s\n' "$Value" ; fi
	fi
}

Lowercase ()
# Description: Converts specified string to lower letter case, using found tools.
# Depends on functions: Is_Executable
# Depends on software packages: grep, tr|awk|sed
{
	local OriginalString="$1"
	
	if [ "$OriginalString" != "" ] ; then
		# Busybox tr has no upper/lower conversion
		if Is_Executable tr && [ "$(tr --help 2>&1 | grep -e ':lower:')" != "" ] ; then
			printf '%s\n' "$OriginalString" | tr '[:upper:]' '[:lower:]'
		else
			if Is_Executable awk ; then
				printf '%s\n' "$OriginalString" | awk '{print tolower($0)}'
			else
				if Is_Executable sed && [ "$(sed --help 2>&1 | grep -e 'GNU')" != "" ] ; then
					printf '%s\n' "$OriginalString" | sed -re 's/([[:upper:]]?)/\L\1/g'
				fi
			fi
		fi
	fi
}

PsOutputValues ()
# Syntax as a function: "$(PsOutputValues "$OutputColumns" "$FilterPid1 $FilterPid2 $FilterPid3...")"
# Description: Parser for ps command, that emulates -A and -o options for old versions without support for it. Only returns (stdout) asked output values.
# Expected parameters:
#	$1	Comma-separated list of keywords to compose columns. Following keywords are the only supported:
#		cmaj_flt,cmd,cmin_flt,comm,cstime,cutime,egid,euid,f,flag,flags,gid,maj_flt,min_flt,ni,nice,nlwp,pgid,pgrp,pid,ppid,pri,priority,rss,rssize,rsz,s,sess,session,sid,state,stime,T,tname,tpgid,tt,tty,uid,utime,vsize,vsz
#		+ specific "sort_pid" (sortable PID: 0001, 0002)
#		Unexpected keywords are directly parsed to ps with modern syntax. Them return '?' in case of error.
#	$2	(optional) Space-separated list of PIDs to restrict to. If not provided, all PIDs will be selected.
# Notes:
#	- No headers are included
#	- Columns are separated by only one space character
#	- Every unknown value is returned as '?'
# Depends on functions: Is_IntegerNr
# Depends on other software: grep sed
{
	local OutputColumns="$1"
	local FilterPids="$2"
	local CurValue=''
	local CurPid=''
	local CurColumn=''
	local CurLine=''
	local PidMaxLen=0
	local Result=$?
	
	if ! Is_IntegerNr $FilterPids ; then
		FilterPids="$(ls -1 /proc/*/cmdline 2>/dev/null | grep -ve 'self' | cut -f 3 -d '/')"
	fi
	if [ "$OutputColumns" = "pid" ] ; then
		# To accelerate simple pids listing
		for CurPid in $FilterPids ; do
			if [ -d /proc/$CurPid ] ; then printf '%s\n' "$CurPid" ; fi
		done
	else
		if [ "$(printf '%s\n' ",${OutputColumns}," | grep -e ',sort_pid,')" != "" ] ; then
			PidMaxLen=0
			for CurPid in $FilterPids ; do
				if [ ${#CurPid} -gt $PidMaxLen ] ; then PidMaxLen=${#CurPid} ; fi
			done
		fi
		OutputColumns="$(printf '%s\n' "$OutputColumns" | tr -s ',' ' ')"
		OutputColumns="$(printf '%s\n' " $OutputColumns " | sed -e 's| state | s |g' | sed -e 's| uid | euid |g' | sed -e 's| gid | egid |g' | sed -e 's| vsize | vsz |g' | sed -e 's| rssize | rss |g' | sed -e 's| rsz | rss |g' | sed -e 's| pgrp | pgid |g' | sed -e 's| session | sess |g')"
		OutputColumns="$(printf '%s\n' " $OutputColumns " | sed -e 's| sid | sess |g' | sed -e 's| tname | tty |g' | sed -e 's| tt | tty |g' | sed -e 's| flags | f |g' | sed -e 's| flag | f |g' | sed -e 's| priority | pri |g' | sed -e 's| nice | ni |g' | sed -e 's| thcount | nlwp |g')"
		for CurPid in $FilterPids ; do
			# A pid called "self" points to analyzer, such as "ls" or "cat". Discarding this.
			if Is_IntegerNr $CurPid ; then
				CurLine=''
				Stat="$(cat /proc/${CurPid}/stat 2>/dev/null | tr -s '\t' ' ' | sed -e 's|^ ||g')"
				StatRest="$(printf '%s\n' "$Stat" | tr -s ' ' | cut -f 2- -d "${ParC}" | sed -e 's|^ ||g')"
				Status="$(cat /proc/${CurPid}/status 2>/dev/null | tr -s '\t' ' ' | tr -s ' ' | sed -e 's|^ ||g')"
				for CurColumn in $OutputColumns ; do
					case "$CurColumn" in
						"sort_pid" ) CurValue="$(printf "%${PidMaxLen}s\n" "$CurPid" | sed -e 's| |0|g')" ;;
						"euid" ) CurValue="$(printf '%s\n' "$Status" | grep -ie '^Uid:' | cut -f 2 -d ':' | tr -s ' ' | sed -e 's|^ ||g' | cut -f 1 -d ' ')" ;;
						"egid" ) CurValue="$(printf '%s\n' "$Status" | grep -ie '^Gid:' | cut -f 2 -d ':' | tr -s ' ' | sed -e 's|^ ||g' | cut -f 1 -d ' ')" ;;
						"vsz" ) CurValue="$(printf '%s\n' "$Status" | grep -ie '^VmSize:' | cut -f 2 -d ':' | tr -s ' ' | sed -e 's|^ ||g' | cut -f 1 -d ' ')" ;;
						"rss" ) CurValue="$(printf '%s\n' "$Status" | grep -ie '^VmRSS:' | cut -f 2 -d ':' | tr -s ' ' | sed -e 's|^ ||g' | cut -f 1 -d ' ')" ;;
						"cmd" )
							CurValue="$(cat /proc/${CurPid}/cmdline 2>/dev/null | tr -s '\0' ' ' | tr -s ' ' | sed -e 's|$ ||g' | sed -e 's| $||g')"	# Command-line arguments come separated by null byles ('\0') and whole line ended too.
							if [ "$CurValue" = "" ] ; then	# comm
								CurValue="$(printf '%s\n' "$Stat" | cut -sf 2 -d "${ParO}" | cut -f 1 -d "${ParC}")"
							fi
							;;
						"pid" )
							CurValue="$(printf '%s\n' "$Stat" | cut -f 1 -d "${ParO}" | cut -f 1 -d ' ')"
							if [ "$CurValue" = "" ] ; then
								CurValue=$CurPid
							fi
							;;
						"comm" ) CurValue="$(printf '%s\n' "$Stat" | cut -sf 2 -d "${ParO}" | cut -f 1 -d "${ParC}")" ;;
						"s" ) CurValue="$(printf '%s\n' "$StatRest" | cut -f 1 -d ' ')" ;;
						"ppid" ) CurValue="$(printf '%s\n' "$StatRest" | cut -f 2 -d ' ')" ;;
						"pgid" ) CurValue="$(printf '%s\n' "$StatRest" | cut -f 3 -d ' ')" ;;
						"sess" ) CurValue="$(printf '%s\n' "$StatRest" | cut -f 4 -d ' ')" ;;
						"tpgid" ) CurValue="$(printf '%s\n' "$StatRest" | cut -f 6 -d ' ')" ;;
						"f" ) CurValue="$(printf '%s\n' "$StatRest" | cut -f 7 -d ' ')" ;;
						"min_flt" ) CurValue="$(printf '%s\n' "$StatRest" | cut -f 8 -d ' ')" ;;
						"cmin_flt" ) CurValue="$(printf '%s\n' "$StatRest" | cut -f 9 -d ' ')" ;;
						"maj_flt" ) CurValue="$(printf '%s\n' "$StatRest" | cut -f 10 -d ' ')" ;;
						"cmaj_flt" ) CurValue="$(printf '%s\n' "$StatRest" | cut -f 11 -d ' ')" ;;
						"utime" ) CurValue="$(printf '%s\n' "$StatRest" | cut -f 12 -d ' ')" ;;
						"stime" ) CurValue="$(printf '%s\n' "$StatRest" | cut -f 13 -d ' ')" ;;
						"cutime" ) CurValue="$(printf '%s\n' "$StatRest" | cut -f 14 -d ' ')" ;;
						"cstime" ) CurValue="$(printf '%s\n' "$StatRest" | cut -f 15 -d ' ')" ;;
						"pri" ) CurValue="$(printf '%s\n' "$StatRest" | cut -f 16 -d ' ')" ;;
						"ni" ) CurValue="$(printf '%s\n' "$StatRest" | cut -f 17 -d ' ')" ;;
						"nlwp" )
							CurValue="$(printf '%s\n' "$StatRest" | cut -f 17 -d ' ')"	# W: Linux before 2.6 always returns "0"
							if [ "$CurValue" = "0" ] ; then
								CurValue="$(ps h p $CurPid -o $CurColumn 2>/dev/null)"
								if ! Is_IntegerNr $CurValue ; then CurValue='0' ; fi
							fi
							;;
						"T" ) CurValue="$(printf '%s\n' "$StatRest" | cut -f 19 -d ' ')" ;;	# Old starttime
#						"tty" ) CurValue="$(ps h p $CurPid -o tty 2>/dev/null)" ;;	# Old "tty" is not the same as modern one.
						* )
							CurValue="$(ps h p $CurPid -o $CurColumn 2>&1 >/dev/null)"
							Result=$?
							if [ $Result -eq 0 ] && [ "$CurValue" = "" ] ; then
								# No error, No stderr
								CurValue="$(ps h p $CurPid -o $CurColumn)"
							else
								CurValue=''
							fi
							;;
					esac
					if [ "$CurValue" = "" ] ; then CurValue='?' ; fi
					CurLine="$CurLine $CurValue"
				done
				if [ -d "/proc/${CurPid}" ] ; then
					# Only if process has not disappeared while collecting data.
					printf '%s\n' "$CurLine" | sed -e 's|^ ||'
				fi
			fi
		done
	fi
}

RecommendedGuiSudo ()
# Syntax as a function: "$(RecommendedGuiSudo)"
# Description: Returns (stdout) best GUI command to ask sudo permissions
# Notes:
#	- To use command, it's only needed to follow it with a space and execution line.  #'
#	- pkexec requires xhost permissions and $DISPLAY setting to work. Implemented.
# Pending:
#	- su-to-root no és una alternativa perquè demana credencial de l'usuari de destinació (contrasenya de root per a root)
# Depends on functions: (none)
# Depends on software packages: grep, lsb-release, kdesudo|kdesu|gksudo|gnomesu|gksu
{
	local OsCodename=''
	local Value=''

#	if [ "$Value" = "" ] ; then Value="$(command -v pkexec 2>/dev/null)" ; fi
#	if [ "$(printf '%s' "$Value" | grep -ie 'pkexec')" != "" ] ; then Value="$Value --disable-internal-agent" ; fi
	# Es prova gksudo i kdesu perque se suposa que s'ha d'estar en sessio d'escriptori grafic. A les versions antigues "gksu" demana contrasenya en Live-CD.  #'
	OsCodename="$(lsb_release -cs 2>/dev/null | grep -ve '/')"	# lsb_release can return n/a
	# Si gksudo no esta disponible: kdesudo (KDE4)  # Dona un error "Command not found" pero segueix l'execucio; cal no acceptar el missatge.  #'
	if [ "$Value" = "" ] ; then Value="$(command -v kdesudo 2>/dev/null)" ; fi
	# Si gksudo ni kdesudo no estan disponible: kdesu (fins KDE3)
	if [ "$Value" = "" ] ; then Value="$(command -v kdesu 2>/dev/null)" ; fi
	if [ "$Value" = "" ] ; then Value="$(command -v kde4su 2>/dev/null)" ; fi
	if [ "$Value" = "" ] && [ "$OsCodename" != "warty" ] && [ "$OsCodename" != "hoary" ] && [ "$OsCodename" != "breezy" ] ; then  # Ubuntu 4.10 en Live-CD demana contrasenya si no es crida gksudo des de terminal. Les 5.04 i 5.10 de vegades tambe. Amb KDE tambe fa el burro.
		Value="$(command -v gksudo 2>/dev/null)"
	fi
	if [ "$Value" = "" ] ; then Value="$(command -v gnomesu 2>/dev/null)" ; fi
#	if [ "$Value" = "" ] && test "xpkexec --disable-internal-agent" != "x" ; then
	if [ "$Value" = "" ] && [ "$(pkexec --help 2>&1 | grep -e '--disable-internal-agent')" != "" ] ; then
		# xpkexec test procedure taken from gparted 0.32.0
		# stty size: Terminal rows and columns: Empty means no visible terminal or bad ioctl.
		if [ "$DISPLAY" != "" ] && [ "$(stty size 2>/dev/null)" = "" ] ; then
			Value="$(command -v pkexec 2>/dev/null) --disable-internal-agent"
		fi
	fi
#	if [ "$Value" = "" ] && [ "$OsCodename" != "warty" ] && [ "$OsCodename" != "hoary" ] && [ "$OsCodename" != "breezy" ] ; then
	if [ "$Value" = "" ] && [ "$OsCodename" != "warty" ] && [ "$OsCodename" != "hoary" ] && [ "$OsCodename" != "breezy" ] ; then
		Value="$(command -v gksu 2>/dev/null)"
	fi
	if [ "$(printf '%s' "$Value" | grep -ie 'gksu' -ie 'gnomesu' -ie 'kdesu')" != "" ] ; then Value="$Value --" ; fi
	if [ "$Value" != "" ] ; then printf '%s\n' "$Value" ; fi
}

PidfileStatus ()
# Only returns exit code about status
# Exit codes same as start-stop-daemon:
#	0: Program is running
#	1: Program is not running and the pid file exists
#	3: Program is not running
#	4: Unable to determine program status
# Depends on functions: Is_Executable Is_IntegerNr
# Depends on software packages: grep, sed, ps/procps
{
	local PidFile="$1"
	local Value=''
	local PID=''
	local SSD="start-stop-daemon"

	if ! Is_Executable "$SSD" && Is_Executable /sbin/start-stop-daemon ; then SSD="/sbin/start-stop-daemon" ; fi
	if [ "$("$SSD" --help 2>&1 | grep -e '--status')" != "" ] ; then
		# Some old versions haven't status parameter.  #'
		"$SSD" --pidfile "$PidFile" --status
		Value=$?
	else
		if [ -f "$PidFile" ] ; then
			PID=$(cat "$PidFile" | sed -e 's| ||g')
			if Is_IntegerNr $PID ; then
				if [ $(ps $PID | wc -l) -ge 2 ] ; then
					Value=0
				else
					Value=1
				fi
			else
				Value=4
			fi
		else
			Value=3
		fi
	fi
	return $Value
}

ExistingPIDs ()
# Description: From PIDs specified, returns (stdout) the existing ones as processes.
# Depends on functions: (none)
# Depends on software packages: sed, ps/procps
{
	local CurrentPid=''
	local Value=''
	
	for CurrentPid in $* ; do
#		if [ "$(pstree $CurrentPid)" != "" ] ; then
		if [ $(ps $CurrentPid | wc -l) -ge 2 ] ; then
			Value="$Value $CurrentPid"
		fi
	done
	Value="$(echo TrimAndSingle $Value | sed -e 's|^TrimAndSingle||g' -e 's|^ ||g')"
	if [ "$Value" != "" ] ; then printf '%s\n' "$Value" ; fi
}

KillPid ()
# Description: Scales signals and walks PID subtree to force a termination.
# Note: Specified PID must exist to find subtree.
# Depends on functions: ExistingPIDs Is_IntegerNr
# Depends on software packages: grep, pstree/psmisc
{
	local Pid=$1
	local TimeoutS=$2
	local PidTree=''
	local CurrentPid=''
	local TimeoutCount=0
	local TempValue=''
	local OldSleep=''
	local MultipleCount=2
	local FractionSecond=0.5
	local LastStatus=0
	local StatusCode=0

	PidTree="$(env COLUMNS=999 pstree -cpt $Pid)"
	if [ "$PidTree" != "" ] ; then
		# Sed upto v3 doesn't support newlines as replacement  #'
		#PidTree="$(echo "$PidTree" | tr -s '(' '\n' | grep -e ')' | cut -f 1 -d ')')"
		TempValue="$(printf '%s\n' "$PidTree" | tr -s '()' ' ')"
		PidTree=''
		for CurrentPid in $TempValue ; do
			if Is_IntegerNr $CurrentPid ; then PidTree="$PidTree $CurrentPid" ; fi
		done
		NextPidTree=''
		for CurrentPid in $PidTree ; do
			if [ "$(pstree $CurrentPid)" != "" ] ; then
				kill -15 $CurrentPid 2>/dev/null
			fi
		done
		TimeoutCount=$((TimeoutS / 2)) ; if [ $TimeoutCount -lt 0 ] ; then TimeoutCount=0 ; fi
		# Sleep upto v2 (and maybe -v4) only support integers
		OldSleep="$(sleep --version | grep -ie sleep | head -n 1 | grep -e ' 0\.' -e ' 1\.' -e ' 2\.' -e ' 3\.' -e ' 4\.' -ie 'invalid')"
		if [ "$OldSleep" != "" ] ; then
			MultipleCount=1
			FractionSecond=1
		fi
		TimeoutCount=$((TimeoutCount * MultipleCount))
		while [ "$(ExistingPIDs $PidTree)" != "" ] && [ $TimeoutCount -gt 0 ] ; do
			sleep $FractionSecond
			TimeoutCount=$((TimeoutCount - 1))
		done
		PidTree="$(ExistingPIDs $PidTree)"
		for CurrentPid in $PidTree ; do
			if [ "$(pstree $CurrentPid)" != "" ] ; then
				kill -9 $CurrentPid 2>/dev/null
			fi
		done
		if [ "$PidTree" != "" ] ; then
			TimeoutCount=$((TimeoutS / 2)) ; if [ $TimeoutCount -lt 0 ] ; then TimeoutCount=0 ; fi
			TimeoutCount=$((TimeoutS - TimeoutCount)) ; if [ $TimeoutCount -lt 0 ] ; then TimeoutCount=0 ; fi
			TimeoutCount=$((TimeoutCount * MultipleCount))
			while [ "$(ExistingPIDs $PidTree)" != "" ] && [ $TimeoutCount -gt 0 ] ; do
				sleep $FractionSecond
				TimeoutCount=$((TimeoutCount - 1))
			done
			if [ "$(ExistingPIDs $PidTree)" != "" ] ; then
				LastStatus=110 ; if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
			fi
		fi
	fi
	if [ "$NozeroStatusToFile" != "" ] && [ ! -f "$NozeroStatusToFile" ] && [ $StatusCode -ne 0 ] ; then echo $StatusCode > "$NozeroStatusToFile" ; fi
	return $StatusCode
}

StopPidFile ()
# Description: Stops daemon and walks whole PID subtree to kill signals.
# Depends on functions: Is_Executable Is_IntegerNr PidfileStatus ExistingPIDs KillPid
# Depends on software packages: pstree/psmisc
{
	local PidFile="$1"
	local TimeoutEachTry=$2
	local TimeoutCount=0
	local MainPid=''
	local PidTree=''
	local CurrentPid=''
	local TempValue=''
	local LastStatus=0
	local SSD="start-stop-daemon"
	local LastStatus=0
	local StatusCode=0

	if [ -f "$PidFile" ] ; then
		if ! Is_Executable "$SSD" && Is_Executable /sbin/start-stop-daemon ; then SSD="/sbin/start-stop-daemon" ; fi
		if [ "$TimeoutEachTry" = "" ] ; then TimeoutEachTry=1 ; fi
		MainPid="$(cat "$PidFile" | sed -e 's| ||g')"
		PidTree="$(env COLUMNS=999 pstree -cpt $MainPid)"
		if [ "$PidTree" != "" ] ; then
			# Sed upto v3 doesn't support newlines as replacement  #'
			#PidTree="$(echo "$PidTree" | tr -s '(' '\n' | grep -e ')' | cut -f 1 -d ')')"
			TempValue="$(printf '%s\n' "$PidTree" | tr -s '()' ' ')"
			PidTree=''
			for CurrentPid in $TempValue ; do
				if Is_IntegerNr $CurrentPid ; then PidTree="$PidTree $CurrentPid" ; fi
			done
			if Is_Executable "$SSD" ; then
				PidfileStatus "$PidFile"
				LastStatus=$?
				"$SSD" --stop --pidfile "$PidFile"
				LastStatus=$?
				if [ $LastStatus -ne 1 ] && [ $LastStatus -ne 3 ] ; then
					# May be running before; we can pass error status result.
					if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
				fi
			fi
			TimeoutCount=$TimeoutEachTry
			while [ "$(pstree -cpt $MainPid)" != "" ] && [ $TimeoutCount -gt 0 ] ; do
				sleep 1
				TimeoutCount=$((TimeoutCount - 1))
			done
			PidTree="$(ExistingPIDs $PidTree)"
			for CurrentPid in $PidTree ; do
				# This walk is necessary because MainPid can be already killed, but not all the tree.
				KillPid $CurrentPid $TimeoutEachTry
				LastStatus=$? ; if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
			done
		fi
		if [ "$(ExistingPIDs $PidTree)" = "" ] ; then
			if [ -f "$PidFile" ] ; then
				rm "$PidFile"
			fi
		else
			LastStatus=110 ; if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
		fi
	else
		LastStatus=95 ; if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
	fi

	if [ "$NozeroStatusToFile" != "" ] && [ ! -f "$NozeroStatusToFile" ] && [ $StatusCode -ne 0 ] ; then echo $StatusCode > "$NozeroStatusToFile" ; fi
	return $StatusCode
}

DaemonizeCommand ()
# Syntax as a sentence: DaemonizeCommand "$PidFile" "$ExecutablePath" $parameters
# Description: 
# Expected parameters:
#	$1	File where to register the forked process PID, useful to control its execution
#	$2	Program pathname as expected by --startas parameter for start-stop-daemon, but necessary in any mode for execution  #do
#	(rest)	Parameters to pass to the executable
# Notes:
#	- Forks with any of start-stop-daemon[Debian] or daemonize[RHEL] or screen
#	- If no daemonize software is available, ampersand method will be used, BUT: Never call DaemonizeCommand inside a $(subshell) call because the $(subshell) only ends when childs end.
#	- An environment variable can be set: DaemonizeWith=screen to force use of "screen" if available.
# PENDENT:
#	- Preveure ús de ampersand
# Depends on functions: Is_Executable Is_IntegerNr Dirname PsOutputValues
# Depends on software packages: grep, sed, dpkg>=1.6|daemonize|screen, ps/procps
{
	local PidFile="$1"
	if [ $# -gt 0 ] ; then shift ; fi
	local ExecutablePath="$1"
	if [ $# -gt 0 ] ; then shift ; fi
	local PidFileDir=''
	local Pid=''
	local SSD="start-stop-daemon"
	local Regexp1=''
	local Regexp2=''
	local ProcessName=''
	local LastStatus=0
	local StatusCode=0

	Pid="$(cat "$PidFile" 2>/dev/null)"
	if Is_IntegerNr $Pid ; then
#		if [ "$(pstree $Pid)" = "" ] ; then
		if [ $(ps $Pid | wc -l) -le 1 ] ; then
			# Dead PID
			rm -f "$PidFile"
		fi
	else
		# Bad $PidFile or not exist
		rm -f "$PidFile"
	fi
	if [ "$DaemonizeWith" != "" ] && ! Is_Executable "$DaemonizeWith" ; then DaemonizeWith='' ; fi
	if [ ! -f "$PidFile" ] ; then
		if ! Is_Executable "$SSD" && Is_Executable /sbin/start-stop-daemon ; then SSD="/sbin/start-stop-daemon" ; fi
		PidFileDir="$(Dirname "$PidFile")"
		if [ ! -d "$PidFileDir" ] ; then
			mkdir -p "$PidFileDir"
			chmod u=rwX,g=rX,o= "$PidFileDir"
		fi
		if Is_Executable "$SSD" && [ "$("$SSD" --help 2>&1 | grep -e '--background')" != "" ] && [ "$("$SSD" --help 2>&1 | grep -e '--make-pidfile')" != "" ] && [ "$DaemonizeWith" = "" ] ; then
			# Without --background option, start-stop-daemon doesn't fork.  #'
			# Without --make-pidfile, PID is difficult to locate (a sub-script should be created).
			"$SSD" --start --pidfile "$PidFile" --make-pidfile --background --startas "$ExecutablePath" -- "$@"
			LastStatus=$? ; if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
		else
			if Is_Executable daemonize && [ "$DaemonizeWith" = "" ] ; then
				daemonize -p "$PidFile" "$ExecutablePath" "$@"
				LastStatus=$? ; if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
			else
				if Is_Executable screen ; then
					ProcessName="$(printf '%s' "$PidFile" | tr -s '/' '\n' | tail -n 1 | cut -f 1 -d '.')"
					if [ "$ProcessName" != "" ] ; then ProcessName="${ProcessName}-" ; fi
					ProcessName="${ProcessName}$(dd if=/dev/urandom count=1 2> /dev/null | cksum | cut -f1 -d ' ')"
					screen -d -m -S "$ProcessName" "$ExecutablePath" "$@"
					LastStatus=$? ; if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
#					Pid="$(echo Trim$(screen -list | sed -e 's|	| |g' | tr -s ' ' | grep -e "\.${ProcessName} (" | cut -f 1 -d '.') | sed -e 's|^Trim||g' | sed -e 's|^ ||g' | sed -e 's| ||g')"
					Pid="$(echo TrimAndSingle $(screen -list | tr -s '\t' ' ' | tr -s ' ' | grep -e "\.${ProcessName} (" | cut -f 1 -d '.') | sed -e 's|^TrimAndSingle||g' -e 's|^ ||g' | sed -e 's| ||g')"
					if Is_IntegerNr $Pid ; then
						printf '%s\n' "$Pid" > "$PidFile"
					fi
				else
#					printf '%s\n' "${sERROR}E: No program to launch command in the background ${ParO}start-stop-daemon/daemonize/screen${ParC}" 1>&2
#					LastStatus=52 ; if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
					"$ExecutablePath" "$@" &
					LastStatus=$? ; if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
					Pid=$!
					if ! Is_IntegerNr $Pid ; then
						# Careful for quotes in arguments
						if [ $# -gt 0 ] ; then
							Regexp1="$(printf '%s\n' "$1" | sed -e 's|\.|\\.|g' | sed -e 's|\*|\\*|g')"
							if [ $# -gt 1 ] ; then
								Regexp2="$(printf '%s\n' "$1" | sed -e 's|\.|\\.|g' | sed -e 's|\*|\\*|g')"
								Pid="$(PsOutputValues sort_pid,pid,cmd | sort | cut -f 2- -d ' ' | grep -e ".* .*$ExecutablePath.* .*${Regexp1}.* .*${Regexp2}" | tail -n 1 | cut -f 1 -d ' ')"
							else
								Pid="$(PsOutputValues sort_pid,pid,cmd | sort | cut -f 2- -d ' ' | grep -e ".* .*$ExecutablePath.* .*${Regexp1}" | tail -n 1 | cut -f 1 -d ' ')"
							fi
						else
							Pid="$(PsOutputValues sort_pid,pid,cmd | sort | cut -f 2- -d ' ' | grep -e ".* .*$ExecutablePath" | tail -n 1 | cut -f 1 -d ' ')"
						fi
					fi
					if Is_IntegerNr $Pid ; then
						printf '%s\n' "$Pid" > "$PidFile"
					fi
				fi
			fi
		fi
	else
		printf '%s\n' "${sERROR}E: Cannot launch a new process over an existing pidfile ${ParO}${PidFile}${ParC} with running PID ${Pid}${fRESET}" 1>&2
		LastStatus=113 ; if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
	fi
	if [ "$NozeroStatusToFile" != "" ] && [ ! -f "$NozeroStatusToFile" ] && [ $StatusCode -ne 0 ] ; then echo $StatusCode > "$NozeroStatusToFile" ; fi
	return $StatusCode
}

TimedExecution ()
# Syntax as a function: $(TimedExecution $TimeoutSeconds $OpportunitiesNr "$StopFile" $command)
# Description: Executes a command with a hard timeout. Returns (stdout) execution's output.  #'
# Expected parameters:
#	$1	Number of seconds to wait the command completes (pased this time, process is killed)
#	$2	Maximum number of executions to try getting a clean exit of the command
#	$3	(optional or empty) File that will be a force signal to terminate inmediately, when exists (will not be removed).
#	(rest)	Command to execute
# Depends on functions: Is_Executable Is_IntegerNr PidfileStatus StopPidFile DaemonizeCommand
# Depends on software packages: grep, dpkg|daemonize
{
	local TimeoutSeconds=$1
	if [ $# -gt 0 ] ; then shift ; fi
	local OpportunitiesNr=$1
	if [ $# -gt 0 ] ; then shift ; fi
	local StopFile="$1"
	if [ $# -gt 0 ] ; then shift ; fi
	local TimedTempDir=''
	local RemainingCount=0
	local RemainingOpportunities=0
	local SuccessTry=0
	local CurrentPid=''
	local PidFile=''
	local ReposeTime=0
	local CurrentParameter=''
	local ParameterNr=-1
#	local MultipleCount=2
#	local FractionSecond=0.5
	local StatusCode_Tmp=0
	local Indentation1='	'
	local LastStatus=0
	local StatusCode=0
	
	if [ ! -d "$DirTemp" ] ; then DirTemp="/run/shm" ; fi
	if [ ! -d "$DirTemp" ] ; then DirTemp="/tmp" ; fi
	if [ ! -d "$DirTempX" ] ; then DirTempX="/tmp" ; fi
	if [ $# -le 0 ] ; then
		printf '%s\n' "${sERROR}E: No command specified for TimedExecution.${fRESET}" 1>&2
		LastStatus=86 ; if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
	fi
	if ! Is_IntegerNr "$TimeoutSeconds" || ! Is_IntegerNr "$OpportunitiesNr" ; then
		printf '%s\n' "${sERROR}E: Bad TimeoutSeconds or OpportunitiesNr for TimedExecution.${fRESET}" 1>&2
		LastStatus=84 ; if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
	fi
	if [ $StatusCode -eq 0 ] ; then
		TimedTempDir="${DirTempX}/TimedExecution.$$"
		rm -fr "$TimedTempDir"
		mkdir "$TimedTempDir"
		chmod u=rwX,g=rX,o= "$TimedTempDir"
		printf '%s\n' '#!/bin/sh' > "${TimedTempDir}/logger.sh"
		chmod u=rwx,go= "${TimedTempDir}/logger.sh" # Closed permissions to secure passwords there
		if ! Is_Executable timeout ; then
			Indentation1=''
		fi
		if [ "$Indentation1" != "" ] ; then
			printf '%s\n' 'if [ "$1" != "timeout" ] ; then' >> "${TimedTempDir}/logger.sh"
			printf '%s\n' "	timeout --signal=9 --kill-after=0 $TimeoutSeconds \"\$0\" timeout" >> "${TimedTempDir}/logger.sh"
			printf '%s\n' '	StatusCode=$?' >> "${TimedTempDir}/logger.sh"
			printf '%s\n' 'else' >> "${TimedTempDir}/logger.sh"
		fi
		for CurrentParameter in "$@" ; do
			ParameterNr=$((ParameterNr + 1))
			if [ $ParameterNr -gt 0 ] ; then
				printf '%s' ' ' >> "${TimedTempDir}/logger.sh"
			else
				printf '%s' "$Indentation1" >> "${TimedTempDir}/logger.sh"
			fi
			if [ "$CurrentParameter" = "" ] ; then
				printf '%s' "''" >> "${TimedTempDir}/logger.sh"
			else
				if [ "$(printf '%s\n' "$CurrentParameter" | grep -e ' ')" != "" ] ; then
					printf '%s' "\"${CurrentParameter}\"" >> "${TimedTempDir}/logger.sh"
				else
					printf '%s' "$CurrentParameter" >> "${TimedTempDir}/logger.sh"
				fi
			fi
		done
		printf '%s\n' " > \"${TimedTempDir}/log.txt\" 2>&1" >> "${TimedTempDir}/logger.sh"
		printf '%s\n' "${Indentation1}StatusCode=\$?" >> "${TimedTempDir}/logger.sh"
		printf '%s\n' "${Indentation1}printf '%s\n' \$StatusCode > \"${TimedTempDir}/StatusCode.num\"" >> "${TimedTempDir}/logger.sh"
		if [ "$Indentation1" != "" ] ; then
			printf '%s\n' 'fi' >> "${TimedTempDir}/logger.sh"
		fi
		printf '%s\n' 'exit $StatusCode' >> "${TimedTempDir}/logger.sh"
		RemainingOpportunities=$OpportunitiesNr
		while [ $RemainingOpportunities -gt 0 ] && [ $SuccessTry -eq 0 ] && [ ! -f "${TimedTempDir}/StatusCode.num" ] && [ ! -f "$StopFile" ] ; do
			PidFile="${TimedTempDir}/logger.pid"
			DaemonizeCommand "$PidFile" "${TimedTempDir}/logger.sh"
			LastStatus=$? ; if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
#			# Sleep upto v2 (and maybe -v4) only support integers
#			OldSleep="$(sleep --version | grep -ie sleep | head -n 1 | grep -e ' 0\.' -e ' 1\.' -e ' 2\.' -e ' 3\.' -e ' 4\.' -ie 'invalid')"
#			if [ "$OldSleep" != "" ] ; then
#				MultipleCount=1
#				FractionSecond=1
#			fi
#			RemainingCount=$((TimeoutSeconds * MultipleCount))
			RemainingCount=$TimeoutSeconds
			while [ $RemainingCount -gt 0 ] && [ $StatusCode -eq 0 ] && [ ! -f "${TimedTempDir}/StatusCode.num" ] && [ ! -f "$StopFile" ] ; do
#				sleep $FractionSecond
				sleep 1
				RemainingCount=$((RemainingCount - 1))
			done
			if [ -f "$PidFile" ] ; then
				PidfileStatus "$PidFile"
				StatusCode_Tmp=$?
				if [ $StatusCode_Tmp -eq 0 ] ; then
					# 0: Program is running
					StatusCode_Tmp=109
				else
					StatusCode_Tmp=0
				fi
				StopPidFile "$PidFile" $TimeoutSeconds
				LastStatus=$? ; if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
				if [ $LastStatus -eq 0 ] ; then LastStatus=$StatusCode_Tmp ; fi
			fi
			if [ -f "${TimedTempDir}/StatusCode.num" ] ; then
				LastStatus="$(cat "${TimedTempDir}/StatusCode.num")"
				if Is_IntegerNr $LastStatus ; then
					if [ $LastStatus -eq 0 ] ; then SuccessTry=1 ; fi
				else
					LastStatus=110
				fi
			else
				if [ $LastStatus -eq 0 ] ; then LastStatus=109 ; fi
			fi
			RemainingOpportunities=$((RemainingOpportunities - 1))
			if [ $SuccessTry -eq 0 ] && [ $RemainingOpportunities -gt 0 ] ; then
				ReposeTime=$((TimeoutSeconds / 2))
				if [ $ReposeTime -gt 15 ] ; then ReposeTime=15 ; fi
				RemainingCount=$ReposeTime
				while [ $RemainingCount -gt 0 ] && [ ! -f "$StopFile" ] ; do
					sleep 1
					RemainingCount=$((RemainingCount - 1))
				done
			fi
		done
		if [ $SuccessTry -eq 0 ] ; then
#			if [ $LastStatus -eq 0 ] ; then LastStatus=109 ; fi
#			if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
			if [ $LastStatus -eq 0 ] && [ $StatusCode -eq 0 ] ; then
				printf '%s\n' "Timeout:${OpportunitiesNr}x${TimeoutSeconds}s." 1>&2
				LastStatus=109
				if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
			fi
			if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
		fi
		if [ -f "${TimedTempDir}/log.txt" ] ; then
			cat "${TimedTempDir}/log.txt"
			rm "${TimedTempDir}/log.txt"
		fi
		rm -r "$TimedTempDir"
	fi
	if [ "$NozeroStatusToFile" != "" ] && [ ! -f "$NozeroStatusToFile" ] && [ $StatusCode -ne 0 ] ; then echo $StatusCode > "$NozeroStatusToFile" ; fi
	return $StatusCode
}

Is_RemoteTcpAlive ()
# Syntax as a function: Is_RemoteTcpAlive "$RemoteHostPort" $TryTimeoutS $MaxTriesNr
# Description: Returns (exitcode 0) TRUE if specified host returns ICMP packets response (ping)
# Use example (without brackets []):
#	if Is_RemoteTcpAlive 192.168.1.2:80 ; then echo "Service available" ; fi
# Expected parameters:
#	$1	target host IP or name & ':' separator & TCP port number
#	$2	(optional, defaults to 2) Max seconds to wait for a result, per each telnet/netcat test
#	$3	(optional, defaults to 1) Max tries to do to get a success result
# Depends on functions: WhereProgram Is_Executable Is_IntegerNr TimedExecution
# Depends on software packages: telnet|netcat
{
	local RemoteHostPort="$1"
	local TryTimeoutS=$2
	local MaxTriesNr=$3
	local RemoteHost=''
	local RemotePort=''
	local TriedNr=0
	local Value=254
	local TestText=''
	local TempFile=''
	local NetCat=''
	local LastStatus=0
	local StatusCode=0
	
	if [ ! -d "$DirTemp" ] ; then DirTemp="/run/shm" ; fi
	if [ ! -d "$DirTemp" ] ; then DirTemp="/tmp" ; fi
	if [ ! -d "$DirTempX" ] ; then DirTempX="/tmp" ; fi
	TempFile="${DirTemp}/Is_RemoteTcpAlive.${$}.txt"
	RemoteHost="$(printf '%s' "$RemoteHostPort" | cut -f 1 -d ':')"
	RemotePort="$(printf '%s' "$RemoteHostPort" | cut -sf 2 -d ':')"
	if ! Is_IntegerNr "$TryTimeoutS" ; then TryTimeoutS=2 ; fi
	if ! Is_IntegerNr "$MaxTriesNr" ; then MaxTriesNr=1 ; fi
	if [ "$RemoteHost" != "" ] && Is_IntegerNr $RemotePort ; then


		if Is_Executable telnet ; then
			while [ $Value -ne 0 ] && [ $TriedNr -lt $MaxTriesNr ] ; do
				TimedExecution $((TryTimeoutS+1)) 1 '' telnet "$RemoteHost" $RemotePort > "$TempFile" 2>&1
				LastStatus=$?	# telnet usually returns exitcode 1 unless user ends with "quit" command.
				TestText="$(cat "$TempFile" 2>/dev/null)"
				rm -f "$TempFile"
				if [ "$TestText" != "" ] ; then
					# In some unexpected circumstance, we cannot catch telnet output.
					if [ "$(printf '%s\n' "$TestText" | grep -ie '^Connected to ')" != "" ] ; then
						Value=0
					fi
				fi
				TriedNr=$((TriedNr + 1))
			done
		fi
		NetCat="$(WhereProgram netcat)"
		if [ "$NetCat" = "" ] && [ "$(nc -h 2>&1 | grep -ie 'netcat')" != "" ] ; then
			NetCat="nc"
		fi
		if Is_Executable $NetCat ; then
			while [ $Value -ne 0 ] && [ $TriedNr -lt $MaxTriesNr ] ; do
				TimedExecution $((TryTimeoutS+1)) 1 '' $NetCat -v -w $TryTimeoutS -z "$RemoteHost" $RemotePort > "$TempFile" 2>&1
				LastStatus=$?	# telnet usually returns exitcode 1 unless user ends with "quit" command.
				TestText="$(cat "$TempFile" 2>/dev/null)"
				rm -f "$TempFile"
				if [ $LastStatus -eq 0 ] || [ "$(printf '%s\n' "$TestText" | grep -ie 'succeeded' -ie ' open$')" != "" ] ; then
					Value=0
				fi
				TriedNr=$((TriedNr + 1))
			done
		fi
		if [ $TriedNr -le 0 ] ; then
			printf '%s\n' "${sERROR}E: Is_RemoteTcpAlive: Could not test TCP port with ${RemoteHost}${fRESET}" 1>&2
			LastStatus=53 ; if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
		else
			StatusCode=$Value
		fi
	else
		printf '%s\n' "${sERROR}E: Is_RemoteTcpAlive: Bad host:port syntax \"$RemoteHostPort\"${fRESET}" 1>&2
		LastStatus=90 ; if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
	fi
	if [ "$NozeroStatusToFile" != "" ] && [ ! -f "$NozeroStatusToFile" ] && [ $StatusCode -ne 0 ] ; then echo $StatusCode > "$NozeroStatusToFile" ; fi
	return $StatusCode
}

DefaultNICs ()
# Sintaxis como funcion: $(DefaultNICs)
# Descripcion: Devuelve (stdout) los nombres de dispositivo que se usan para salir a internet/WAN, uno por línea
# Notas:
#	- Sólo se detecta un dispositivo si está habilitado (up).
#	- Function previously named DispositivoRedPredeterminado when only returned 1 NIC
#	- Alternativa con iproute2:
#	  ip r l | grep -ie '^default ' | tr -s '\t' ' ' | tr -s ' ' '\n' | tail -n 1
# To do:
#	- Use alternative from iproute2: ss
# Depends on functions: Is_Executable
# Depends on software packages: grep, sed, net-tools|iproute
{
	local IPPrincipal=''
	local ListaDispositivos=''
	local IpRoute=''
	local List=''
	local OneValue=''
	
	if Is_Executable netstat ; then
		List="$(netstat -rn 2>/dev/null | tr -s '\t' ' ' | tr -s ' ' | grep -e '^0\.0\.0\.0 ')"
		IFS="$(printf '\n\b')" ; for CurLine in $List ; do unset IFS
			OneValue="$(printf '%s\n' "$CurLine" | tr -s ' ' '\n' | tail -n 1)"
			if [ "$OneValue" != "" ] && [ "$(cat /proc/net/dev | tr -s ' ' | sed -e 's|^ ||g' | grep -e "^${OneValue}:")" != "" ] ; then printf '%s\n' "$OneValue" ; fi
		done
	fi
	if [ "$OneValue" = "" ] ; then
		IpRoute="$(command -v ip 2>/dev/null)"
		if [ "$IpRoute" = "" ] && [ -x /sbin/ip ] ; then IpRoute="/sbin/ip" ; fi
		if [ "$IpRoute" = "" ] && [ -x /bin/ip ] ; then IpRoute="/bin/ip" ; fi
		if [ "$IpRoute" = "" ] && [ -x /usr/sbin/ip ] ; then IpRoute="/usr/sbin/ip" ; fi
		if [ "$IpRoute" = "" ] && [ -x /usr/bin/ip ] ; then IpRoute="/usr/bin/ip" ; fi
		if [ "$IpRoute" != "" ] ; then
			export LANG=en
			List="$($IpRoute route | tr -s '\t' ' ' | tr -s ' ' | grep -ie '^default via .* dev ')"
			IFS="$(printf '\n\b')" ; for CurLine in $List ; do unset IFS
				OneValue="$(printf '%s\n' "$CurLine" | tr -s ' ' '\n' | tail -n 1)"
				if [ "$OneValue" != "" ] && [ "$(ip link show "$OneValue" 2>/dev/null)" != "" ] ; then printf '%s\n' "$OneValue" ; fi
			done
			if [ "$OneValue" = "" ] ; then
				IPPrincipal="$($IpRoute route | tr -s '\t' ' ' | tr -s ' ' | grep -e '^default ' | grep -e ' src ' | head -n 1 | sed -re 's| |\n|g' | grep -ve '^$' | tail -n 1)"
				if [ "$IPPrincipal" != "" ] ; then
					Value="$($IpRoute address show | tr -s '\t' ' ' | tr -s ' ' | grep -e " ${IPPrincipal}/" | head -n 1 | sed -e 's| |\n|g' | grep -ve '^$' | sed -e 's|@if..*||g' | tail -n 1)"
				else
					Value="$($IpRoute route | tr -s '\t' ' ' | tr -s ' ' | grep -e '^default ' | grep -e ' dev ' | head -n 1 | sed -e 's| |\n|g' | grep -ve '^$' | head -n 5 | tail -n 1)"
				fi
				Value="$(echo TrimAndSingle $Value | sed -e 's|^TrimAndSingle||g' -e 's|^ ||g')"
				if [ "$Value" != "" ] && [ "$(ip link show "$OneValue" 2>/dev/null)" != "" ] ; then printf '%s\n' "$Value" ; fi
			fi
		fi
	fi
}

NicIpAcquirement ()
# Syntax as a function: $(NicIpAcquirement $Nic)
# Description: Returns configuration method applied to a network interface.
# Possible values returned are: dhcp static none unknown
# Expected parameters:
#	$1	Existing NIC name
# Depends on functions: PsOutputValues
# Depends on software packages: grep, sed, iproute
{
	local Nic="$1"
	local DhcpNics=''
	local DhcpControllers=''
	local CurrentController=''
	local CurrentNic=''
	local Ip=''
	local IpRoute=''
	local Value='unknown'
	
	# h = newer --no-headers
	DhcpControllers="$(PsOutputValues cmd | grep -e '/dhclient .' -e ' dhclient .' | grep -ve 'grep -')"
	IFS="$(printf '\n\b')" ; for CurrentController in $DhcpControllers ; do unset IFS
		CurrentNic="$(echo TrimAndSingle $CurrentController | sed -e 's|^TrimAndSingle||g' -e 's|^ ||g' | tr -s ' ' '\n' | tail -n 1)"
		if [ "$CurrentNic" = "$Nic" ] ; then
			Value="dhcp"
		fi
	done
	if [ "$Value" = "unknown" ] ; then
		IpRoute="$(command -v ip 2>/dev/null)"
		if [ "$IpRoute" = "" ] && [ -x /sbin/ip ] ; then IpRoute="/sbin/ip" ; fi
		if [ "$IpRoute" = "" ] && [ -x /bin/ip ] ; then IpRoute="/bin/ip" ; fi
		if [ "$IpRoute" = "" ] && [ -x /usr/sbin/ip ] ; then IpRoute="/usr/sbin/ip" ; fi
		if [ "$IpRoute" = "" ] && [ -x /usr/bin/ip ] ; then IpRoute="/usr/bin/ip" ; fi
		if [ "$IpRoute" != "" ] ; then
			export LANG=en
			Ip="$($IpRoute address show dev "$Nic" scope global | grep -e 'inet ' | sed -e 's|.* inet ||g')"
			Ip="$(printf '%s\n' "$(OneWord () { printf '%s' $1; }; OneWord $Ip)" | cut -f 1 -d '/')"
			if [ "$Ip" != "" ] ; then
				if [ "$($IpRoute address show dev "$Nic" scope global | grep -e ' dynamic ')" != "" ] ; then
					Value="dhcp"
				else
					Value="static"
				fi
			else
				Value="none"
			fi
		fi
	fi
	if [ "$Value" != "" ] ; then printf '%s\n' "$Value" ; fi
}

BridgeMembers ()
# Syntax as a function: "$(BridgeMembers "$TheBridge")"
# Description: Returns (stdout) names of attached NICs; one name per line
# Expected parameters:
#	$1	Existing bridge name
# Depends on functions: Is_Executable
# Depends on software packages: grep, sed, iproute2|net-tools&bridge-utils
{
	local TheBridge="$1"
	local CurrentLine=''
	local CurrentMac=''
	local CurrentNIC=''
	local IfConfig=''
	local BrCtl=''
	local Value=''
	
	if Is_Executable bridge && [ "$(ip -V 2>/dev/null | grep -e iproute2)" != "" ] ; then
		Value="$(bridge link show | grep -e ": .*:.*<.*>.* master $TheBridge " | cut -f 2 -d ' ' | cut -f 1 -d ':')"
	else
		IfConfig="$(command -v ifconfig 2>/dev/null)"
		if [ "$IfConfig" = "" ] && [ -x /sbin/ifconfig ] ; then IfConfig="/sbin/ifconfig" ; fi
		if [ "$IfConfig" = "" ] && [ -x /bin/ifconfig ] ; then IfConfig="/bin/ifconfig" ; fi
		if [ "$IfConfig" = "" ] && [ -x /usr/sbin/ifconfig ] ; then IfConfig="/usr/sbin/ifconfig" ; fi
		if [ "$IfConfig" = "" ] && [ -x /usr/bin/ifconfig ] ; then IfConfig="/usr/bin/ifconfig" ; fi
		BrCtl="$(command -v brctl 2>/dev/null)"
		if [ "$BrCtl" = "" ] && [ -x /sbin/brctl ] ; then BrCtl="/sbin/brctl" ; fi
		if [ "$BrCtl" = "" ] && [ -x /bin/brctl ] ; then BrCtl="/bin/brctl" ; fi
		if [ "$BrCtl" = "" ] && [ -x /usr/sbin/brctl ] ; then BrCtl="/usr/sbin/brctl" ; fi
		if [ "$BrCtl" = "" ] && [ -x /usr/bin/brctl ] ; then BrCtl="/usr/bin/brctl" ; fi
		if [ "$IfConfig" != "" ] ; then
			NICs="$($IfConfig | grep -ve '^ ' -ve '^$' | cut -f 1 -d ' ' | cut -f 1 -d ':')"
		fi
		IFS="$(printf '\n\b')" ; for CurrentLine in $($BrCtl showmacs "$TheBridge" | tail -n +2) ; do unset IFS
			IsLocal="$(OneWord () { printf '%s' $3; }; OneWord $CurrentLine)"
			if [ "$IsLocal" = "yes" ] ; then
				CurrentMac="$(OneWord () { printf '%s' $2; }; OneWord $CurrentLine)"
				for CurNIC in $NICs ; do
					NicInfo="$(env LANG=en $IfConfig $CurNIC)"
					NicInfo="$(echo TrimAndSingle $NicInfo | sed -e 's|^TrimAndSingle||g' -e 's|^ ||g')"
					if [ "$(printf '%s\n' "$NicInfo" | grep -ie " HWaddr.${CurrentMac}" -ie " ether ${CurrentMac}")" != "" ] ; then
						#printf '%s\n' "$CurNIC"
						if [ "$(printf '%s' "$Value" | grep -e "^${CurNIC}$")" = "" ] ; then
							Value="$(printf '%s\n' "$Value" ; printf '%s\n' "$CurNIC")"
						fi
					fi
				done
			fi
		done
	fi
	if [ "$Value" != "" ] ; then
		printf '%s' "$Value" | grep -ve '^$'
	fi
}

ComparaVersions ()
# Sintaxis com a funció: $(ComparaVersions $Versio1 $Versio2)
# Descripció:	Torna (stdout) un d'aquests tres valors: "<" "=" ">" en funció de si la $Versio1 és inferior
#		, igual o superior a la $Versio2
# Notes:
#	- S'esperen valors de tipus "2.6.39" (números separats entre punts)
#	- Alternativa Debian: dpkg --compare-versions $Versio1 $Comparison $Versio2 && echo true
#	  on $Comparison pot ser:
#		lt le eq ne ge gt	(versió en blanc és anterior a les altres)
#		lt-nl le-nl ge-nl gt-nl	(versió en blanc és posterior a les altres)
#		< << <= = >= >> >
# Depends on functions: Is_IntegerNr
# Depends on other software: grep, sed
{
	local Versio1="$1"
	local Versio2="$2"
	local InternalEnd="$3"
	local Versio1Numeros=''
	local Versio2Numeros=''
	local Numero1Actual=''
	local Numero2Actual=''
	local Newest=''
	local Result=0
	local ResultN=0
	local Valor=''
	
	if [ "$Versio1" != "" ] && [ "$Versio2" != "" ] ; then
		if [ "$InternalEnd" = "" ] ; then
			Versio1Numeros="$(printf '%s' "$Versio1" | tr -s '.' ' ')"
			Versio2Numeros="$(printf '%s' "$Versio2" | tr -s '.' ' ')"
			for Numero1Actual in $Versio1Numeros ; do
				if [ "$Valor" = "" ] ; then
					Numero2Actual="$(OneWord () { printf '%s' $1; }; OneWord $Versio2Numeros)"
					Numero1Actual="$(printf '%s' "$Numero1Actual" | tr -s '.' ' ' | sed -e 's|\([a-z]\)| \1 |g' | tr -s '+:~-' ' ' | tr -s ' ' '.')"
					Numero2Actual="$(printf '%s' "$Numero2Actual" | tr -s '.' ' ' | sed -e 's|\([a-z]\)| \1 |g' | tr -s '+:~-' ' ' | tr -s ' ' '.')"
					if [ "$Numero2Actual" != "" ] ; then
						if [ "$Numero1Actual" != "$Numero2Actual" ] ; then
							Valor="$(ComparaVersions $Numero1Actual $Numero2Actual end)"
						fi
						Versio2Numeros="$(RestaParaules () { shift ; echo TrimAndSingle $* | sed -e 's|^TrimAndSingle||g' -e 's|^ ||g' ; }; RestaParaules $Versio2Numeros)"
					else
						# versio1 té més números que versio2
						if [ "$Numero1Actual" != "0" ] ; then
							Valor=">"
						fi
					fi
				fi
			done
			if [ "$Valor" = "" ] ; then
				Numero2Actual="$(OneWord () { printf '%s' $1; }; OneWord $Versio2Numeros)"
				if [ "$Numero2Actual" != "" ] && [ "$Numero2Actual" != "0" ] ; then
					# versio2 té més números que versio1
					Valor="<"
				else
					Valor="="
				fi
			fi
		else
			Versio1Numeros="$(printf '%s' "$Versio1" | tr -s '.' ' ' | sed -e 's|\([a-z]\)| \1 |g' | tr -s '+:~-' ' ')"
			Versio2Numeros="$(printf '%s' "$Versio2" | tr -s '.' ' ' | sed -e 's|\([a-z]\)| \1 |g' | tr -s '+:~-' ' ')"
			for Numero1Actual in $Versio1Numeros ; do
				if [ "$Valor" = "" ] ; then
					Numero2Actual="$(OneWord () { printf '%s' $1; }; OneWord $Versio2Numeros)"
					if [ "$Numero2Actual" != "" ] ; then
						if [ "$Numero1Actual" != "$Numero2Actual" ] ; then
							if Is_IntegerNr $Numero1Actual ; then
								if Is_IntegerNr $Numero2Actual ; then
									if [ $Numero1Actual -lt $Numero2Actual ] ; then Valor="<" ; fi
									if [ $Numero1Actual -gt $Numero2Actual ] ; then Valor=">" ; fi
								else
									Valor="<"
								fi
							else
								if Is_IntegerNr $Numero2Actual ; then
									Valor=">"
								else
									Newest="$(printf '%s\n' "$Numero1Actual $Numero2Actual" | tr -s ' ' '\n' | grep -ve '^$' | sort | tail -n 1)"
									if [ "$Newest" = "$Numero1Actual" ] ; then
										Valor=">"
									else
										Valor="<"
									fi
								fi
							fi
						fi
						Versio2Numeros="$(RestaParaules () { shift ; echo TrimAndSingle $* | sed -e 's|^TrimAndSingle||g' -e 's|^ ||g' ; }; RestaParaules $Versio2Numeros)"
					else
						# versio1 té més números que versio2
						if [ "$Numero1Actual" != "0" ] ; then
							Valor=">"
						fi
					fi
				fi
			done
			if [ "$Valor" = "" ] ; then
				Numero2Actual="$(OneWord () { printf '%s' $1; }; OneWord $Versio2Numeros)"
				if [ "$Numero2Actual" != "" ] && [ "$Numero2Actual" != "0" ] ; then
					# versio2 té més números que versio1
					Valor="<"
				else
					Valor="="
				fi
			fi
		fi
	else
		if [ "${Versio1}${Versio2}" = "" ] ; then
			# No sabem cap versio
			Valor=""
		else
			# Versio coneguda sempre és més nova que un programa que no donava versió.
			if [ "$Versio1" = "" ] ; then
				Valor="<"
			else
				if [ "$Versio2" = "" ] ; then
					Valor=">"
				fi
			fi
		fi
	fi
	if [ "$Valor" != "" ] && [ $ResultN -eq 0 ] ; then printf '%s\n' "$Valor" ; fi
	return $ResultN
}

RespostaLletra ()
# Sintaxi com a funcio: $(RespostaLletra $JaEspecificada)
# Descripció: Llegeix una resposta del teclat (cal polsar ENTER) i retorna la inicial de la resposta (en minúscula si és possible - a Maemo no)
# Paràmetres esperats:
#	$1	(opcional) Tractar aquesta cadena en comptes de demanar-la de teclat.
# Depends on functions: Lowercase
# Depends on other software: (none)
{
	JaEspecificada="$1"
	if [ "$JaEspecificada" = "" ] ; then read JaEspecificada ; fi
	JaEspecificada="$(printf '%s' "$JaEspecificada" | cut -c 1)"
	JaEspecificada="$(Lowercase "$JaEspecificada")"
	if [ "$JaEspecificada" != "" ] ; then printf '%s\n' "$JaEspecificada" ; fi
}

UnidadesOpticas ()
# Devuelve una lista de dispositivos que corresponden a CD o DVD (uno por línea)
# Pendiente:
#	- Sacarle partido a blkid, que devuelve atributos de la unidad.
#	- Sacar partido a: lshw -class disk
# Notes:
#	- Needs SuperUser (root) permissions to detect something
{
#	local Valor=''
	local ElDmesg=''
	local CurValue=''
	local Value=''
	
	# Ojo que el fichero /var/log/dmesg a veces existe sólo con la frase "Nothing has been logged yet"
	ElDmesg="$(cat /var/log/dmesg 2>/dev/null | grep -ie '.:.:.:.*Attached.*CD' -ie '.:.:.:.*Attached.*DVD' -ie '..*:..*DVD-ROM' -ie '..*:..*CDROM')"
	if [ "$ElDmesg" = "" ] ; then ElDmesg="$(dmesg 2>/dev/null)" ; fi
	ElDmesg="$(printf '%s\n' "$ElDmesg" | grep -ie '.:.:.:.*Attached.*CD' -ie '.:.:.:.*Attached.*DVD' -ie '..*:..*DVD-ROM' -ie '..*:..*CDROM')"
	IFS="$(printf '\n\b')" ; for LiniaActual in $ElDmesg ; do unset IFS
		CurValue="$(printf '%s' "$LiniaActual" | grep -ie '.Attached.' | tr -s ' ' '\n' | tail -n 1)"
		if [ "$CurValue" = "" ] ; then CurValue="$(printf '%s' "$LiniaActual" | cut -f 1 -d ':')" ; fi
		if [ "$CurValue" != "" ] ; then
			CurValue="$(find /dev 2>/dev/null | grep -e "/${CurValue}$" | head -n 1)"
			if [ "$(printf '%s\n' "$Value" | grep -e "^${CurValue}$")" = "" ] ; then
				Value="$(printf '%s\n' "$Value" ; printf '%s\n' "$CurValue")"
			fi
		fi
	done
	if [ "$Value" != "" ] ; then
		printf '%s\n' "$Value" | grep -ve '^$'
	fi
}

Is_PartitionedMedia ()
# Syntax as a function: Is_PartitionedMedia "$MediaPath"
# Description: Returns (exitcode) TRUE if specified file or device has first sector marked as 55AAh boot sector (either MBR or GPT).
# Use example (without brackets []):
#	if Is_PartitionedMedia file.img ; then echo "Hard disk" ; fi
# Notes:
#	- When querying a device, superuser (root) permissions are necessary to detect something.
# Depends on functions: (none)
# Depends on other software: (none)
{
	local MediaPath="$1"
	local TrueResult=254
	
	if [ "$(cat "$MediaPath" 2>/dev/null | head -c 512 | tail -c 2 | xxd -p | grep -ie '55aa$')" != "" ] ; then
		# exitcode==0 is TRUE; any other value is FALSE for ShellScripting
		TrueResult=0
	fi
	return $TrueResult
}

Is_OpticalMedia ()
# Syntax as a function: Is_OpticalMedia "$MediaPath"
# Description: Returns (exitcode 0) TRUE if specified file or device is detected as a typical CD/DVD iso image, or FALSE otherwise.
# Use example (without brackets []):
#	if Is_OpticalMedia file.iso ; then echo "CD/DVD" ; fi
# Notes:
#	- When querying a device, superuser (root) permissions are necessary to detect something. FOUND AN AUDIO-CD NOT RECOGNISED.
#	- Assuming .ISO and .UDF file extensions to be optical images.
# Depends on functions: Is_Executable
# Depends on software packages: sed grep
{
	local MediaPath="$1"
	local TrueCode=254 # 254=FALSE
	
	if [ "$(cat "$MediaPath" 2>/dev/null | head -c 1048576 | head -n 1 | sed -ne '/CD001/p')" != "" ] ; then
		# exitcode==0 is TRUE; any other value is FALSE for ShellScripting
		TrueCode=0
	else
		if Is_Executable xdg-mime && [ "$(xdg-mime query filetype "$MediaPath" 2>/dev/null | grep -e '-dvd' -e '-cd' -e 'dvd$' -e '-cd$' | grep -ve 'netcdf')" != "" ] ; then
			TrueCode=0
		fi
	fi
	if [ $TrueCode -ne 0 ] && [ -f "$MediaPath" ] && [ "$(printf '%s\n' "$MediaPath" | grep -ie '\.ISO$' -ie '\.UDF$')" != "" ] ; then
		TrueCode=0
	fi
	return $TrueCode
}

Is_RomMedia ()
# Syntax as a function: Is_RomMedia "$MediaPath"
# Description: Returns (exitcode) TRUE if specified file or device is detected to be readonly or recommended for (such as optical)
# Use example (without brackets []):
#	if Is_RomMedia /dev/sr0 ; then echo "ROM" ; fi
# Notes:
#	- When querying a device, superuser (root) permissions are necessary to detect something.
#	- Assuming .ISO extension to be write-protective except if there is a partitioned boot sector.
# Depends on functions: Is_OpticalMedia Is_PartitionedMedia
# Depends on other software: (none)
{
	local MediaPath="$1"
	local TrueResult=254
	
	if [ "$(printf '%s\n' "$MediaPath" | grep -ie '\.iso$')" != "" ] ; then
		Is_PartitionedMedia "$MediaPath"
		TrueResult=$?
		if [ $TrueResult -eq 0 ] ; then
			# Partitioned; assuming no ROM for only file extension
			# exitcode==0 is TRUE; any other value is FALSE for ShellScripting
			TrueResult=254
		else
			# not partitioned; assuming CD/DVD ROM image for file extension
			# exitcode==0 is TRUE; any other value is FALSE for ShellScripting
			TrueResult=0
		fi
	else
		Is_OpticalMedia "$MediaPath"
		TrueResult=$?
	fi
	return $TrueResult
}

IniSectionContent ()
# Syntax as a function: $(IniSectionContent "$FileOrContent" "$SectionName")
# Expected parameters:
#	$1	Path/name of file to query. If not exists as a file, string will be treated as content to look into.
#	$2	[section name] without brackets []. Example: "global"
#		specifying "[]" returns file content before any section declaration.
# Notes:
#	- Includes section header 
# Depends on functions:	(none)
# Depends on software packages: grep, sed
{
	local FileOrContent="$1"
	local SectionName="$2"
	local LinesNr=0
	local Value=''
	
	if [ "$FileOrContent" != "" ] && [ "$SectionName" != "" ] ; then
		if [ -f "$FileOrContent" ] ; then
			Value="$(cat "$FileOrContent")"
		else
			Value="$FileOrContent"
		fi
		if [ "$SectionName" != "[]" ] ; then
			Value="$(printf '%s\n' "$Value" | sed -rne "/^[[:blank:]]*[[]${SectionName}[]]/,//p")"
			if [ "$Value" != "" ] ; then
				printf '%s\n' "$Value" | head -n 1	# Print before being filtered
				LinesNr="$(printf '%s\n' "$Value" | wc -l)"
				# Omit current section header
				Value="$(printf '%s\n' "$Value" | tail -n $((LinesNr - 1)))"
				Value="$(printf '%s\n' "$Value" | sed -re '/^[[:blank:]]*[[].*[]]/q')"
				LinesNr="$(printf '%s\n' "$Value" | wc -l)"
				if [ "$(printf '%s\n' "$Value" | tail -n 1 | grep -e '^ [[].*[]]' -e '^[[].*[]]')" != "" ] && [ $LinesNr -ge 2 ] ; then
					# Omit next section header
					Value="$(printf '%s\n' "$Value" | head -n $((LinesNr - 1)))"
				else
					# Omit when desired section is empty and first line is next section's header
					Value="$(printf '%s\n' "$Value" | grep -ve '^ [[].*[]]' -ve '^[[].*[]]')"
				fi
			fi
		else
			Value="$(printf '%s\n' "$Value" | sed -re '/^[[:blank:]]*[[].*[]]/q' | grep -ve '^ [[].*[]]' -ve '^[[].*[]]')"
		fi
	fi
	if [ "$Value" != "" ] ; then printf '%s\n' "$Value" ; fi
}

IniVarValue ()
# Syntax as a function: $(IniVarValue "$FileOrContent" "$VariableName" "$SectionName" "$NotFoundValue" "$NameValueSeparator" "$EndVariableSymbol" "$DefaultsFile")
# Expected parameters:
#	$1	Path/name of file to query. If not exists as a file, string will be treated as content to look into.
#	$2	Variable name to query (case insensitive)
#	$3	(optional or empty) [section name] without brackets []. Default (empty): no section consideration. Examples: "global" ""
#	$4	(optional or empty) Value to return in case of not finding the variable in any file. Default; empty string.
#	$5	(optional or empty) Separator between variable name and assigned value. Default: "=". Examples: "=" ":="
#	$6	(optional or empty) End variable/assignation mark, to be omited from value. Default (empty): No end mark. Example: ";"
#	$7	(optional or empty) File path where to get DefaultValue from, if found. A found value prevails over 4th parameter (DefaultValue)
# To Do:
#	- This (or another function) to load more than one variable at once.
# Notes:
#	- if section is not specified or empty, returns last match from whole file content.
#	- if section is "[]", queries only file content before any [section] declaration.
# Depends on functions: IniSectionContent
# Depends on software packages: grep, sed
{
	local FileOrContent="$1"
	local VariableName="$2"
	local SectionName="$3"
	local NotFoundValue="$4"
	local NameValueSeparator="$5"
	local EndVariableSymbol="$6"
	local LinesNr=0
	local SectionContent=''
	local SeparatorMask='IVVtmpbHckF2LMB4tmpWz2coasdb3tmpX7LuyGTvrW'
	local NotFoundKey='IVVtmpStZrypNMzntmpgKqLEd5E5ttmpIWW5wemyCW'
	local Value=''
	
	if [ "$FileOrContent" != "" ] ; then
		if [ "$NameValueSeparator" = "" ] ; then NameValueSeparator='=' ; fi
		if [ "$SectionName" = "" ] ; then
			if [ -f "$FileOrContent" ] ; then
				SectionContent="$(cat "$FileOrContent")"
			else
				SectionContent="$FileOrContent"
			fi
		else
			SectionContent="$(IniSectionContent "$FileOrContent" "$SectionName")"
		fi
		Value="$(printf '%s\n' "$SectionContent" | tr -s '\t' ' ' | grep -ie "^${VariableName}${NameValueSeparator}" -ie "^ ${VariableName}${NameValueSeparator}" -ie "^ ${VariableName} ${NameValueSeparator}" | tail -n 1 | sed -e "s|${NameValueSeparator}|${SeparatorMask}|")"
		if [ "$Value" != "" ] ; then
			# Variable found; let's separate value.
			Value="$(printf '%s\n' "$Value" | sed -e "s|.*${SeparatorMask}||")"
			Value="$(expr "$Value" : "[ ]*\(.*[^ ]\)[ ]*$")"	# Trim
			if [ "$EndVariableSymbol" != "" ] ; then
				Value="$(printf '%s\n' "$Value" | sed -e "s|${EndVariableSymbol}$||")"
				Value="$(expr "$Value" : "[ ]*\(.*[^ ]\)[ ]*$")"	# Trim
			fi
			if [ "$(printf '%s\n' "$Value" | grep -e '^"' | grep -e '"$')" != "" ] ; then
				# Double quotes
				Value="$(printf '%s\n' "$Value" | cut -f 2- -d '"' | sed -e 's|"$||')"
			else
				if [ "$(printf '%s\n' "$Value" | grep -e "^'" | grep -e "'$")" != "" ] ; then
					# Single quotes
					Value="$(printf '%s\n' "$Value" | cut -f 2- -d "'" | sed -e "s|'$||")"
				fi
			fi
		else
			Value="$NotFoundKey"
		fi
	else
		Value="$NotFoundKey"
	fi
	if [ "$Value" = "$NotFoundKey" ] ; then
		if [ "$DefaultsFile" != "$FileOrContent" ] && [ -f "$DefaultsFile" ] ; then
			Value="$(IniVarValue "$DefaultsFile" "$VariableName" "$SectionName" "$NotFoundValue" "$NameValueSeparator" "$EndVariableSymbol" '')"
		else
			Value="$NotFoundValue"
		fi
	fi
	if [ "$Value" != "" ] ; then printf '%s\n' "$Value" ; fi
}

SetIniVarValue ()
# Syntax as a sentence: SetIniVarValue "$File" "$VariableName" "$SectionName" "$NewValue" "$NameValueSeparator" "$PreComment"
# Expected parameters:
#	$1	Path/name of file to query
#	$2	Variable name to query
#	$3	(optional or empty) [section name] without brackets []. Examples: "global" ""
#	$4	(optional or empty) Value to write for the variable entry.
#	$5	(optional or empty) Separator between variable name and assigned value. Examples: "=" ":=". Default is "="
#	$6	(optional or empty) Line to precede variable's line if it must be added. Comment mark should be included.
#		PreComment can contain escaped \n to be converted into line breaks.
# To Do:
#	- Process content separated by section (treat different variable as in different section)
#	- This (or another function) to set more than one variable at once.
# Notes:
#	- if section is not specified or empty, sets matches in the whole file.
#	- if section is "[]", sets variable only before any [section] declaration in the file.
#	- Some blank lines can be lost in resulting file content
# Depends on functions: Dirname IniSectionContent
# Depends on software packages: grep, sed
{
	local File="$1"
	local VariableName="$2"
	local SectionName="$3"	# Optional or empty (examples: "global" "")
	local NewValue="$4"	# If quotes are needed ("value") must be already contained in the supplied value ("\"value\""). Same with EndVariableSymbol.
	local NameValueSeparator="$5"	# Optional or empty (example: ":=") Default is "="
	local PreComment="$6"	# Optional line to precede variable's line if it must be added. Comment mark should be included.
	local OldContent=''
	local Part1=''
	local SectionContent=''
	local Part2=''
	local LastStatus=0
	local StatusCode=0
	
	if [ "$File" != "" ] && [ "$VariableName" != "" ] ; then
		if [ ! -f "$File" ] ; then
			mkdir -p "$(Dirname "$File")"
			touch "$File"
		fi
		if [ -f "$File" ] ; then
			if [ "$NameValueSeparator" = "" ] ; then NameValueSeparator="=" ; fi
			OldContent="$(cat "$File")"
			if [ "$SectionName" != "" ] ; then
				OldContentLinesNr=$(printf '%s\n' "$OldContent" | wc -l)
				if [ "$SectionName" = "[]" ] ; then
					SectionContent="$(printf '%s\n' "$OldContent" | sed -re '/^[[:blank:]]*[[].*[]]/q' | grep -ve '^[[].*[]]' -ve '^ [[].*[]]')"
					Part1LinesNr=$(printf '%s\n' "$SectionContent" | wc -l)
					cat /dev/null > "$File"
					LastStatus=$? ; if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
					if [ "$(printf '%s\n' "$SectionContent" | tr -s '\t' ' ' | tr -s ' ' | grep -ie "^${VariableName}${NameValueSeparator}" -ie "^ ${VariableName}${NameValueSeparator}" -ie "^ ${VariableName}${NameValueSeparator}" -ie "^ ${VariableName} ${NameValueSeparator}")" = "" ] ; then
						if [ "$SectionContent" != "" ] ; then
							printf '%s\n' "$SectionContent" >> "$File"
							LastStatus=$? ; if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
						fi
						if [ "$PreComment" != "" ] ; then
							if [ "$(cat "$File" 2>/dev/null)" != "" ] && [ "$(cat "$File" | tail -n 1)" != "" ] ; then
								printf '%s\n' "" >> "$File"
								LastStatus=$? ; if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
							fi
							printf '%s\n' "$PreComment" | sed -e 's|\\n|\n|g' >> "$File"
							LastStatus=$? ; if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
						fi
						printf '%s\n' "${VariableName}${NameValueSeparator}${NewValue}" >> "$File"
						LastStatus=$? ; if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
					else
						printf '%s\n' "$SectionContent" | sed -re "s|^([[:blank:]]*)(${VariableName})([[:blank:]]*)(${NameValueSeparator})([[:blank:]]*).*|\1\2\3\4\5${NewValue}|" >> "$File"
						LastStatus=$? ; if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
					fi
					printf '%s\n' "$OldContent" | tail -n $((OldContentLinesNr - Part1LinesNr)) >> "$File"
				else
					if [ "$(printf '%s\n' "$OldContent" | grep -e "^[[]${SectionName}[]]" -e "^ [[]${SectionName}[]]")" != "" ] ; then
						# Case sensitive to match sed that cannot be insensitive with q/p commands
						Part1="$(printf '%s\n' "$OldContent" | sed -re "/^[[:blank:]]*[[]${SectionName}[]]/q")"
						Part1LinesNr=$(printf '%s\n' "$Part1" | wc -l)
						Part1LinesNr=$((Part1LinesNr - 1))
						Part1="$(printf '%s\n' "$Part1" | grep -ive "^[[]${SectionName}[]]" -ive "^ [[]${SectionName}[]]")"
						SectionContent="$(IniSectionContent "$File" "$SectionName")"
						SectionLinesNr=$(printf '%s\n' "$SectionContent" | wc -l)
						Part2="$(printf '%s\n' "$OldContent" | tail -n $((OldContentLinesNr - Part1LinesNr - SectionLinesNr)))"
						cat /dev/null > "$File"
						LastStatus=$? ; if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
						if [ "$Part1" != "" ] ; then
							printf '%s\n' "$Part1" >> "$File"
							LastStatus=$? ; if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
						fi
						if [ "$(printf '%s\n' "$SectionContent" | tr -s '\t' ' ' | tr -s ' '| grep -ie "^${VariableName}${NameValueSeparator}" -ie "^ ${VariableName}${NameValueSeparator}" -ie "^ ${VariableName}${NameValueSeparator}" -ie "^ ${VariableName} ${NameValueSeparator}")" = "" ] ; then
							printf '%s\n' "$SectionContent" >> "$File"
							LastStatus=$? ; if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
							if [ "$PreComment" != "" ] ; then
								printf '%s\n' "$PreComment" | sed -e 's|\\n|\n|g' >> "$File"
								LastStatus=$? ; if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
							fi
							printf '%s\n' "${VariableName}${NameValueSeparator}${NewValue}" >> "$File"
							LastStatus=$? ; if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
						else
							printf '%s\n' "$SectionContent" | sed -re "s|^([[:blank:]]*)(${VariableName})([[:blank:]]*)(${NameValueSeparator})([[:blank:]]*).*|\1\2\3\4\5${NewValue}|" >> "$File"
							LastStatus=$? ; if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
						fi
						if [ "$Part2" != "" ] ; then
							printf '%s\n' "$Part2" >> "$File"
							LastStatus=$? ; if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
						fi
					else
						printf '%s\n' "[${SectionName}]" >> "$File"
						LastStatus=$? ; if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
						if [ "$PreComment" != "" ] ; then
							printf '%s\n' "$PreComment" | sed -e 's|\\n|\n|g' >> "$File"
							LastStatus=$? ; if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
						fi
						printf '%s\n' "${VariableName}${NameValueSeparator}${NewValue}" >> "$File"
						LastStatus=$? ; if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
					fi
				fi
			else
				if [ "$(printf '%s\n' "$OldContent" | tr -s '\t' ' ' | tr -s ' '| grep -ie "^${VariableName}${NameValueSeparator}" -ie "^ ${VariableName}${NameValueSeparator}" -ie "^ ${VariableName}${NameValueSeparator}" -ie "^ ${VariableName} ${NameValueSeparator}")" = "" ] ; then
					if [ "$PreComment" != "" ] ; then
						printf '%s\n' "$PreComment" | sed -e 's|\\n|\n|g' >> "$File"
						LastStatus=$? ; if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
					fi
					printf '%s\n' "${VariableName}${NameValueSeparator}${NewValue}" >> "$File"
					LastStatus=$? ; if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
				else
					printf '%s\n' "$OldContent" | sed -re "s|^([[:blank:]]*)(${VariableName})([[:blank:]]*)(${NameValueSeparator})([[:blank:]]*).*|\1\2\3\4\5${NewValue}|i" > "$File"
					LastStatus=$? ; if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
				fi
			fi
		fi
	else
		printf '%s\n' "E: SetIniVarValue: File and/or VariableName not specified." 1>&2
		LastStatus=81 ; if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
	fi
	return $StatusCode
}

GetOrSetIniVarValue ()
# Syntax as a function: $(GetOrSetIniVarValue "$File" "$VariableName" "$SectionName" "$DefaultValue" "$NameValueSeparator" "$EndVariableSymbol" "$PreComment" "$ReadOnly" "$DefaultsFile")
# Expected parameters:
#	$1	Path/name of file to query
#	$2	Variable name to query (case insensitive)
#	$3	(optional or empty) [section name] without brackets []. Examples: "global" ""
#	$4	(optional or empty) Value to return in case of not finding the variable in any file. It's used to write the new variable entry too.
#	$5	(optional or empty) Separator between variable name and assigned value. Examples: "=" ":=". Default is "="
#	$6	(optional or empty) End variable/assignation mark, to be omited from value and to be written when needed. Example: ";"
#	$7	(optional or empty) Line to precede variable's line if it must be added. Comment mark should be included.
#	$8	(optional or empty) "1" or "ro" if $File must not be modified
#	$9	(optional or empty) File path where to get DefaultValue from, if found. A found value prevails over 4th parameter (DefaultValue)
# Notes:
#	- if section is not specified or empty, treats whole file content.
#	- if section is "[]", treats only file content before any [section] declaration.
#	- PreComment can contain escaped \n to be converted into line breaks.
# Depends on functions: IniVarValue SetIniVarValue
# Depends on software packages: grep, sed
{
	local File="$1"
	local VariableName="$2"
	local SectionName="$3"
	local DefaultValue="$4"	# If quotes are needed ("value") must be already contained in the supplied value ("\"value\""). Same with EndVariableSymbol.
	local NameValueSeparator="$5"
	local EndVariableSymbol="$6"
	local PreComment="$7"
	local ReadOnly="$8"
	local DefaultsFile="$9"
	local NotFoundKey='GOSIVVtmpStZrypNMzntmpgKqLEd5E5ttmpIWW5wemyCW'
	local Value=''
	local LastStatus=0
	local StatusCode=0
	
	Value="$(IniVarValue "$File" "$VariableName" "$SectionName" "$NotFoundKey" "$NameValueSeparator" "$EndVariableSymbol" "$DefaultsFile")"
	if [ "$Value" = "$NotFoundKey" ] ; then
		if [ "$ReadOnly" != "1" ] && [ "$ReadOnly" != "ro" ] ; then
			SetIniVarValue "$File" "$VariableName" "$SectionName" "${DefaultValue}${EndVariableSymbol}" "$NameValueSeparator" "$PreComment"
			LastStatus=$? ; if [ $StatusCode -eq 0 ] ; then StatusCode=$LastStatus ; fi
		fi
		Value="$DefaultValue"
		# EndVariableSymbol does not come with DefaultValue
		if [ "$(printf '%s\n' "$Value" | grep -e '^"' | grep -e '"$')" != "" ] ; then
			# Double quotes
			Value="$(printf '%s\n' "$Value" | cut -f 2- -d '"' | sed -e 's|"$||')"
		else
			if [ "$(printf '%s\n' "$Value" | grep -e "^'" | grep -e "'$")" != "" ] ; then
				# Single quotes
				Value="$(printf '%s\n' "$Value" | cut -f 2- -d "'" | sed -e "s|'$||")"
			fi
		fi
	fi
	if [ "$Value" != "" ] ; then printf '%s\n' "$Value" ; fi
	return $StatusCode
}

MemoriaRamDisponible ()
# Sintaxi com a funció: $(MemoriaRamDisponible $Unit)
# Descripcio: Retorna la quantitat de bytes no ocupats per processos, és a dir, que es podrien arribar a utilitzar.
# Expected parameters:
#	$1	(optional) Same as "free" command allows for unit: -b -k -m -g (bytes, KiB, MiB, GiB)
# Depends on functions: Is_IntegerNr
# Depends on other software: grep, procps
{
	local Unit="$1"
	local Value=''
	local Factor=1
	local SystemReport=''
	local Result=0
	
	free $Unit >/dev/null 2>&1
	Result=$?
	if [ $Result -ne 0 ] ; then
		# Buxybox's (v1) doesn't support unit parameter for integrated free command
		case "$Unit" in
			"-b" ) Factor=0 ;;
			"-k" ) Factor=1 ;;
			"-m" ) Factor=1024 ;;
			"-g" ) Factor=$((1024*1024)) ;;
		esac
		Unit=''
	fi
	SystemReport="$(env LANG=en free $Unit)"
	if [ "$(printf '%s\n' "$SystemReport" | grep -e 'buf.*cache.*avail')" != "" ] ; then
		# Columns format since procps-ng ~ 3.3.12
		Value="$(printf '%s\n' "$SystemReport" | grep -ie '^Mem:' | cut -f 2- -d ':')"
		Value="$(printf '%s' $(OneWord () { printf '%s' $6; }; OneWord $Value))"
	else
		# Columns format until procps-ng ~ 3.3.10
		Value="$(printf '%s\n' "$SystemReport" | grep -ie 'buf.*/cache:' | cut -f 2- -d ':')"
		Value="$(printf '%s' $(OneWord () { printf '%s' $2; }; OneWord $Value))"
	fi
	if Is_IntegerNr $Value ; then
		if [ $Factor -eq 0 ] ; then
			Value=$(($Value * 1024))
		else
			Value=$(($Value / $Factor))
		fi
		printf '%s\n' "$Value"
	fi
}

NewMac ()
# Syntax as a function: $(NewMac "$ControlFile")
# Description: returns (stdout) a MAC address using the counter available in $ControlFile
# Notes:	- The MAC will include as first 3 bytes the reserved for Citrix/XEN use "00:16:3E"
#		  and the 4th byte will be "F1" as this function's mark. There will be 16 bit space
#		  for the generated addresses.
#		- The last byte will never be "00"
# Depends on functions: IniVarValue SetIniVarValue
# Depends on other software: bc
{
	local ControlFile="$1"
	local Result=0
	local CounterValue=0
	local GeneratedByte1=''
	local GeneratedByte2=''
	local Value=''
	
	if [ "$ControlFile" = "" ] ; then ControlFile="$HOME/.newmac.conf" ; fi
	CounterValue=$(IniVarValue "$ControlFile" "NewMacCounter")
	if [ "$CounterValue" = "" ] ; then
		# A random start number gives the possibility of different NewMacs between computers.
		CounterValue=$(dd if=/dev/urandom count=1 2> /dev/null | cksum | cut -f 1 -d ' ')
		if [ $CounterValue -gt 65535 ] ; then
			CounterValue="$(printf '%s' "$CounterValue" | cut -c -5)"
			if [ $CounterValue -gt 65535 ] ; then
				CounterValue=$(($CounterValue - 65536))
			fi
		fi
	else
		CounterValue=$((CounterValue + 1))
	fi
	if [ $CounterValue -gt 65535 ] ; then CounterValue=1 ; fi
	GeneratedByte2=$(($CounterValue % 256))
	if [ $GeneratedByte2 -eq 0 ] ; then
		GeneratedByte2=1
		CounterValue=$((CounterValue + 1))
	fi
	GeneratedByte2="$(printf '%s\n' "obase=16; $GeneratedByte2" | bc)"
	while [ ${#GeneratedByte2} -lt 2 ] ; do
		GeneratedByte2="0${GeneratedByte2}"
	done
	GeneratedByte1=$(($CounterValue / 256))
	GeneratedByte1="$(printf '%s\n' "obase=16; $GeneratedByte1" | bc)"
	while [ ${#GeneratedByte1} -lt 2 ] ; do
		GeneratedByte1="0${GeneratedByte1}"
	done
	Value="00:16:3E:F1:${GeneratedByte1}:${GeneratedByte2}"
	SetIniVarValue "$ControlFile" NewMacCounter '' $CounterValue
	Result=$?
	if [ $Result -eq 0 ] ; then printf '%s\n' "$Value" ; fi
	return $Result
}

NextWordTo ()
# Syntax as a function: $(NextWordTo "$Phrase" $WordToDetect $NrPositionsNext)
# Description:	Explores the phrase word by word, and when finds $WordToDetect counts 
#		$NrPositionsNext and returns (stdout) this word.
# Example: $(NextWordTo "una vegada caminava amunt" "vegada" 2) = "amunt"
# Notes:	If $WordToDetect is detected more than one time, all next words are returned;
# Example: $(NextWordTo "una cadira i una taula" "una" 1) = "cadira taula"
# Depends on functions: (none)
# Depends on other software: grep, sed
{
	local Phrase="$1"
	local WordToDetect="$2"
	local NrPositionsNext=$3
	if [ "$NrPositionsNext" = "" ] ; then NrPositionsNext=1 ; fi
	local CurrentWord=''
	local WordDetected=''
	local CurrentPosition=0
	local Value=''
	
	if [ "$Phrase" != "" ] && [ "$WordToDetect" != "" ] ; then
		for CurrentWord in $Phrase ; do
			if [ "$WordDetected" = "" ] ; then
				if [ "$(printf '%s\n' "$CurrentWord" | grep -ie "^$WordToDetect$")" != "" ] ; then
					WordDetected="$CurrentWord"
				fi
			else
				CurrentPosition=$(($CurrentPosition + 1))
				if [ $CurrentPosition -eq $NrPositionsNext ] ; then
					Value="$Value $CurrentWord"
					CurrentPosition=0
					WordDetected=''
				fi
			fi
		done
	fi
	Value="$(echo TrimAndSingle $Value | sed -e 's|^TrimAndSingle||g' -e 's|^ ||g')"
	if [ "$Value" != "" ] ; then printf '%s\n' "$Value" ; fi
}


##### SPECIFIC FUNCTIONS TO THIS SCRIPT #####

StringWithParameters ()
# Returns (echo) first found one of searched parameters in string. Otherwise, returns nothing ""
# Example: "$(StringWithParameters 'a b c' 'a')" == "a"
# Example: "$(StringWithParameters 'a b c' 'z' 'a')" == "a"
# Example: "$(StringWithParameters 'a b c' 'b' 'c')" == "b"
# Example: "$(StringWithParameters 'a,b,c' 'b')" == ""
# Example: "$(StringWithParameters 'a=1 b c' 'a')" == "a=1"
# Example: "$(StringWithParameters 'a=1 b c a=2' 'a')" == "a=1"
{
	local ParametersString="$1"
#	local ParameterSearched="$2"
	if [ $# -gt 0 ] ; then shift ; fi
	local CurSearched=''
	local Value=''
	
	for CurSearched in "$@" ; do
		if [ "$Value" = "" ] ; then
			Value="$(printf '%s\n' "$ParametersString" | tr -s '\t ' '\n' | grep -e "^${CurSearched}$" -e "^${CurSearched} " -e " ${CurSearched}$" -e " ${CurSearched} " -e "^${CurSearched}=" -e " ${CurSearched}=" | head -n 1)"
			if [ "$Value" = "" ] && [ "$(printf '%s' "$CurSearched" | grep -e ' ')" != "" ] ; then
				# Parameters with spaces, such as '-display curses'
				Value="$(printf '%s\n' "$ParametersString" | tr -s '\t' ' ' | grep -e "^${CurSearched}$" -e "^${CurSearched} " -e " ${CurSearched}$" -e " ${CurSearched} " -e "^${CurSearched}=" -e " ${CurSearched}=" | head -n 1)"
			fi
			if [ "$Value" != "" ] ; then
				printf '%s\n' "$Value"
			fi
		fi
	done
}

StringWithoutParameter ()
# Returns (echo) string without searched parameter at all
# Example: "$(StringWithoutParameter 'a b c' 'a')" == "b c"
# Example: "$(StringWithoutParameter 'a,b,c' 'b')" == "a,b,c"
# Example: "$(StringWithoutParameter 'a=1 b c' 'a')" == "b c"
# Example: "$(StringWithoutParameter 'a=1 b c a=2' 'a')" == "b c"
{
	local ParametersString="$1"
	local ParameterSearched="$2"
	local CurrentFound=''
	local Value=''
	
	Value="$ParametersString"
	CurrentFound="$(printf '%s\n' "$Value" | tr -s '\t ' '\n' | grep -e "^${ParameterSearched}$" -e "^${ParameterSearched} " -e " ${ParameterSearched}$" -e " ${ParameterSearched} " -e "^${ParameterSearched}=" -e " ${ParameterSearched}=" | head -n 1)"
	while [ "$CurrentFound" != "" ] ; do
		Value="$(printf '%s\n' "$Value" | sed -e "s|^${CurrentFound}$||g" -e "s|^${CurrentFound} ||g" -e "s| ${CurrentFound}$||g" -e "s| ${CurrentFound} | |g")"
		CurrentFound="$(printf '%s\n' "$Value" | tr -s '\t ' '\n' | grep -e "^${ParameterSearched}$" -e "^${ParameterSearched} " -e " ${ParameterSearched}$" -e " ${ParameterSearched} " -e "^${ParameterSearched}=" -e " ${ParameterSearched}=" | head -n 1)"
	done
	if [ "$Value" != "" ] ; then
		printf '%s\n' "$Value"
	fi
}

InformarEsdeveniment ()
# Enregistra el text a la bitàcola i/o el mostra al terminal en funció de
# si s'està en una sessió gràfica o no.
{
	echo "$(date +'%F %T') $1" 2>/dev/null >> "$BitacoraPerfil"
	if [ "$SessioEscriptori" = "" ] ; then
		echo "$1"
	fi
}

MissatgeAssincron ()
{
	local ElText="$1"
	if [ ! -d "$DirTemp" ] ; then DirTemp="/run/shm" ; fi
	if [ ! -d "$DirTemp" = "" ] ; then DirTemp="/tmp" ; fi
	InformarEsdeveniment "[${ShortProfileID}/${RunID}] ${ElText}"
	if [ "$SessioEscriptori" != "" ] ; then
		if Is_Executable "$SSD" ; then
			"$SSD" --pidfile "${DirTemp}/matromu-xmessage.pid" --background --start --startas $(WhereProgram xmessage) -- -center -buttons Ok:101 -default Ok "$(echo "[${ShortProfileID}] $HandyName" ; echo "$ElText")"
		else
			screen -d -m xmessage -center -buttons Ok:101 -default Ok "$(echo "[${ShortProfileID}] $HandyName" ; echo "$ElText")"
		fi
	fi
}

MissatgeSincron ()
# El mateix que MissatgeAssincron(), però esperant a què es polsi el botonet.
{
	local ElText="$1"
	InformarEsdeveniment "[${ShortProfileID}/${RunID}] ${ElText}"
	if [ "$SessioEscriptori" != "" ] ; then
		xmessage -center -buttons Ok:101 -default Ok "$(echo "[${ShortProfileID}] $HandyName" ; echo "$ElText")"
	fi
}

GetQemuBin ()
# Syntax as a function: $(GetQemuBin "$PlatformType")
# Description: Returns (stdout) the name of the executable for Qemu
# Expected parameters:
#	$1	Can be one of the available qemu launchers, such as:
#		arm microblaze mipsel sh4 x86_64 cris mips ppc sh4eb i386 mips64 ppc64 sparc m68k mips64el ppcemb sparc64
{
	local PlatformType="$1"
	local TypeDetected=""
	local Value=""
	
	Value="qemu-system-${PlatformType}"
	if ! Is_Executable "$Value" ; then
		TypeDetected="$(uname -m | tr "[:upper:]" "[:lower:]")"
		if [ "$(printf '%s\n' "$TypeDetected" | cut -c 1-3)" = "arm" ] ; then
			TypeDetected="arm"
		fi
		Value="qemu-system-${TypeDetected}"
	fi
	if ! Is_Executable "$Value" ; then
		TypeDetected="$(uname -m | tr "[:upper:]" "[:lower:]")"
		if [ "$(printf '%s\n' "$TypeDetected" | cut -c 1-3)" = "arm" ] ; then
			TypeDetected="arm"
		fi
		Value="kvm-system-${TypeDetected}"
	fi
	if ! Is_Executable "$Value" ; then
		Value="qemu-system-i386"
	fi
	if ! Is_Executable "$Value" ; then
		Value="kvm-system-i386"
	fi
	if ! Is_Executable "$Value" ; then
		Value="qemu"
	fi
	if ! Is_Executable "$Value" ; then
		Value="kvm"
	fi
	if Is_Executable "$Value" ; then
		printf '%s\n' "$Value"
	fi
}

GetPlatformParameters ()
# Syntax as a function: $(GetPlatformParameters "$CpuBin" "$WantedMachine" "$WantedCpu" "$ExtraParameters")
# Description: Returns (echo) the value for -cpu parameter (the last available)
# Expected parameters:
#	$1	The Qemu's executable to use, such as "qemu-system-i386"
#	$2	The machine to emulate (optional)
#	$3	The specific processor to emulate (optional)
#	$4	Other parameters manually specified for Qemu
{
	local CpuBin="$1"
	local WantedMachine="$2"
	local WantedCpu="$3"
	local ExtraParameters="$4"
	local Value=""
	
	if [ "$(StringWithParameters "$ExtraParameters" "-M")" = "" ] ; then
		if [ "$(echo "$CpuBin" | grep -iE "(^qemu-system-|^kvm-system-)")" = "" ] && [ "$WantedMachine" = "" ] ; then
			# If the platform wasn't selected with the binary.
			Value="$("$CpuBin" -M ? | grep -ive ":" | grep -ie "default" | tr -s " " "\n" | tr -s "[]" "\n" | head --lines=1)"
			if [ "$Value" = "" ] ; then
				Value="$("$CpuBin" -M ? | grep -ive ":" | tr -s " " "\n" | tr -s "[]" "\n" | head --lines=1)"
			fi
			if [ "$Value" != "" ] ; then
				Value="-M $Value"
			fi
		else
			if [ "$WantedMachine" != "" ] ; then
				Value="-M $WantedMachine"
			fi
		fi
	fi
	if [ "$(StringWithParameters "$ExtraParameters" "-cpu")" = "" ] ; then
		if [ "$WantedCpu" != "" ] ; then
			Value="$Value -cpu $WantedCpu"
		else
			if [ "$SistemaVirtualitza" != "" ] && [ "$(echo "$ModeKVM" | grep -e '-no-kvm')" = "" ] ; then
				Value="$Value -cpu host"
			else
				if [ "$BitsSistema" = "64" ] ; then
					Value="$Value -cpu qemu64"
				else
					Value="$Value -cpu qemu32"
				fi
			fi
		fi
	fi
	if [ "$(StringWithParameters "$ExtraParameters" "-vga")" = "" ] ; then
		if [ "$(echo ",${DisplayChannels}," | grep -ie ",curses,")" != "" ] && [ "$("$CpuBin" --help 2>&1 | grep -e '^-vga .*virtio')" != "" ] ; then
			Value="$Value -vga virtio"
		else
			if [ "$("$CpuBin" --help 2>&1 | grep -e '^-vga .*qxl')" != "" ] ; then
				Value="$Value -vga qxl"
			fi
		fi
	fi
	if [ "$Value" != "" ] ; then
		echo " $(echo $Value)"
	fi
}

PrefixSudo ()
{
	local Value='sudo'
	if [ "$SessioEscriptori" != "" ] ; then
		Value="$(RecommendedGuiSudo)"
		if [ "$Value" = "" ] ; then Value='sudo' ; fi
	fi
	printf '%s\n' "$Value"
}

PreguntarCrearDisco ()
{
	local ImagefilePath="$1"
	local NombreActual=""
	local Respuesta=0
	local ImagenComo=''
	local ImageSizeMiB=''
	local preallocation=''
	
	NombreActual="$(basename "$ImagefilePath")"
	if [ "$NombreActual" = "." ] ; then NombreActual="$(basename "$ImagefilePath")" ; fi
	if Is_Executable dd || Is_Executable truncate ; then
		if [ "$SessioEscriptori" != "" ] ; then
			echo "$(echo "El fichero $NombreActual no existe." ; echo "¿Lo quieres crear como disco duro virtual?")" | xmessage -center -buttons "Ligero y creciente:101,Integro:102,No crear:103" -default "Ligero y creciente" -file -
			ImagenComo=$?
		else
			echo "El fichero $NombreActual no existe."
			echo "¿Lo quieres crear como disco duro virtual?"
			echo "[S]Ligero y creciente [R]Integro [N]No crear"
			ImagenComo="$(RespostaLletra)"
			case "$ImagenComo" in
				"s" )	ImagenComo=101	;;
				"S" )	ImagenComo=101	;;
				"l" )	ImagenComo=101	;;
				"L" )	ImagenComo=101	;;
				"c" )	ImagenComo=101	;;
				"C" )	ImagenComo=101	;;
				"i" )	ImagenComo=102	;;
				"I" )	ImagenComo=102	;;
				"r" )	ImagenComo=102	;;
				"R" )	ImagenComo=102	;;
				"n" )	ImagenComo=103	;;
				"N" )	ImagenComo=103	;;
				* )	ImagenComo=103	;;
			esac
		fi
	else
		if [ "$SessioEscriptori" != "" ] ; then
			echo "$(echo "El fichero $NombreActual no existe." ; echo "¿Lo quieres crear como disco duro virtual?")" | xmessage -center -buttons "Si crear integro:102,No crear:103" -default "Si crear integro" -file -
			ImagenComo=$?
		else
			echo "El fichero $NombreActual no existe."
			echo "¿Lo quieres crear como disco duro virtual?"
			echo "[R]Si crear integro [N]No crear"
			ImagenComo="$(RespostaLletra)"
			case "$ImagenComo" in
				"s" )	ImagenComo=102	;;
				"S" )	ImagenComo=102	;;
				"l" )	ImagenComo=102	;;
				"L" )	ImagenComo=102	;;
				"c" )	ImagenComo=102	;;
				"C" )	ImagenComo=102	;;
				"i" )	ImagenComo=102	;;
				"I" )	ImagenComo=102	;;
				"r" )	ImagenComo=102	;;
				"R" )	ImagenComo=102	;;
				"n" )	ImagenComo=103	;;
				"N" )	ImagenComo=103	;;
				* )	ImagenComo=103	;;
			esac
		fi
	fi
	if [ $ImagenComo -eq 101 ] || [ $ImagenComo -eq 102 ] ; then
		if [ $ImagenComo -eq 102 ] ; then
			preallocation='preallocation'
		fi
		if [ "$SessioEscriptori" != "" ] ; then
			TimeComment=""
			if [ $ImagenComo -eq 102 ] && Is_Executable fallocate ; then TimeComment=" (tarda)" ; fi
			echo '¿Cuan grande debe ser el nuevo fichero?' | xmessage -center -buttons "1.44M:101,16MiB:102,128MiB:103,512MiB:104,2GiB:105,8GiB:106,16GiB:107,64GiB${TimeComment}:108" -file -
			Respuesta=$?
			case $Respuesta in
				101 )	ImageSizeMiB='1.44'
						;;
				102 )	ImageSizeMiB='16'
						;;
				103 )	ImageSizeMiB='128'
						;;
				104 )	ImageSizeMiB='512'
						;;
				105 )	ImageSizeMiB='2048'
						;;
				106 )	ImageSizeMiB='8192'
						;;
				107 )	ImageSizeMiB='16384'
						;;
				108 )	ImageSizeMiB='65536'
						;;
			esac
		else
			echo '¿Cuan grande debe ser el nuevo fichero?'
			echo 'Escribe el numero de mebibytes (MiB) o incluye un punto para precisar en kibibytes (ej: 1.440)'
			read ImageSizeMiB
		fi
		Unidad="M"
		if [ "$(printf '%s\n' "$ImageSizeMiB" | grep -e '\.')" != "" ] && [ "$(printf '%s\n' "$ImageSizeMiB" | grep -e '\..*\.')" = "" ] ; then
			Unidad="K"
			Megas="$(printf '%s\n' "$ImageSizeMiB" | cut -f 1 -d '.')"
			Kilos="$(printf '%s\n' "$ImageSizeMiB" | cut -f 2- -d '.')"
			while [ ${#Kilos} -lt 3 ] ; do Kilos="${Kilos}0" ; done
			ImageSizeMiB="${Megas}${Kilos}"
			while [ "$(printf '%s\n' "$ImageSizeMiB" | grep -e '^0')" != "" ] ; do
				ImageSizeMiB="$(printf '%s\n' "$ImageSizeMiB" | sed -e 's|^0||g')"
			done
		fi
		if Is_IntegerNr $ImageSizeMiB ; then
			if [ "$preallocation" = "" ] ; then
#				qemu-img create -f raw "$ImagefilePath" ${ImageSizeMiB}${Unidad}
				truncate -s ${ImageSizeMiB}${Unidad} "$ImagefilePath" 2>/dev/null
				Result=$?
				if [ $Result -ne 0 ] ; then
					rm -f "$ImagefilePath"
					dd if=/dev/zero "of=${ImagefilePath}" bs=1 count=0 seek=${ImageSizeMiB}${Unidad}
				fi
			else
				if [ "$Unidad" = "M" ] ; then
					fallocate --length $(($ImageSizeMiB * 1024 * 1024)) "$ImagefilePath" 2>/dev/null
					Result=$?
				else
					# Unidad K
					fallocate --length $(($ImageSizeMiB * 1024)) "$ImagefilePath" 2>/dev/null
					Result=$?
				fi
				if [ $Result -ne 0 ] ; then
					rm -f "$ImagefilePath"
					dd if=/dev/zero "of=${ImagefilePath}" bs=1${Unidad} count=$ImageSizeMiB
				fi
			fi
		fi
	fi
}

GetSetRenamedParameter ()
#
{
	local ConfigurationFile="$1"
	local OldName="$2"
	local NewName="$3"
	local DefaultValue="$4"
	local DefaultDescription="$5"
	local NotFoundValue="NoENCoNTRADo@71191866"
	local Value=""
	
#	Value="$(ValorVariableFichero "$ConfigurationFile" "$OldName" "$NotFoundValue")"
	Value="$(IniVarValue "$ConfigurationFile" "$OldName" '' "$NotFoundValue" '=')"
	if [ "$Value" = "$NotFoundValue" ] ; then
#		Value="$(ParametroEstablecidoConf "$ConfigurationFile" "$NewName" "$DefaultValue" "$DefaultDescription")"
		Value="$(GetOrSetIniVarValue "$ConfigurationFile" "$NewName" '' "$DefaultValue" '=' '' "$DefaultDescription" "$ReadOnly")"
	fi
	if [ "$Value" != "" ] ; then
		echo "$Value"
	fi
}

NetChannel_Setup ()
# Fills global variables:
#	GlobalNetworkSpec
#	PreviesXarxa
#	PosteriorsXarxa
{
	local NetChannel_Value="$1"
	local UserOptions=''
	local OptionsSpec=''
	local UserSpec=''
	local NicModel=''
	local NicModelSpec=''
	local NicMac=''
	local MacSpec=''
	local NicSpec=''
	local DefaultModel='rtl8139'
	local SambaOptions=''
	local SambaSpec=''
	local BrCtl=''
	local IfConfig=''
	local DhClient=''
	local VlanSpec=''
	local SoftwareNicSpec=''
	
	if ! Is_IntegerNr $VlanNr ; then
		VlanNr=0
	else
		VlanNr=$(($VlanNr + 1))
	fi
	NicSpec="$(printf '%s\n' "$NetChannel_Value" | cut -f 1 -d '|')"
	if [ "$NicSpec" = "user" ] || [ "$(echo "$NicSpec" | grep -e '^user,')" != "" ] || [ "$(echo "$NicSpec" | grep -e '^user/')" != "" ] || [ "$(echo "$NicSpec" | grep -e '^user:')" != "" ] ; then
		UserSpec="$(printf '%s\n' "$NicSpec" | cut -f 1 -d ',')"
#		NicModel="$(printf '%s\n' "$UserSpec" | cut -sf 2 -d '/')"
		NicModel="$(printf '%s\n' "$NicSpec" | cut -sf 2 -d '/')"
#		NicMac="$(printf '%s\n' "$UserSpec" | cut -sf 3 -d '/')"
		NicMac="$(printf '%s\n' "$NicSpec" | cut -sf 3 -d '/')"
	else
		NicModel="$(printf '%s\n' "$NicSpec" | cut -sf 1 -d "/")"
		NicMac="$(echo "$NicSpec" | cut -sf 2 -d "/")"
	fi
	if [ "$NicModel" = "" ] ; then NicModel="$DefaultModel" ; fi
	if [ "$NicMac" != "" ] ; then
		if [ "$(ComparaVersions $QemuVersion 2.8.0)" = ">" ] ; then
			MacSpec=",mac=${NicMac}"
		else
			MacSpec=",macaddr=${NicMac}"
		fi
	fi
	# vhost-net es pot utilitzar quan hi ha interfície «tap»
	if [ "$(echo "$NicModel" | grep -ie 'virtio')" != "" ] ; then
		if [ "$(lsmod | grep -e '^vhost.net ')" = "" ] ; then
			if [ $(id -u) -eq 0 ] ; then
				# http://www.linux-kvm.com/content/how-maximize-virtio-net-performance-vhost-net
				modprobe vhost-net 2>/dev/null
			else
				printf '%s\n' "W: Kernel module vhost-net needs to be loaded but root permissions are required." 1>&2
			fi
		fi
		if [ "$(lsmod | grep -e '^vhost.net ')" != "" ] ; then SoftwareNicSpec=',vhost=on' ; fi
	fi
	if [ "$(ComparaVersions $QemuVersion 2.0)" = "<" ] ; then
		# -net syntax
		if [ "$NicModel" = "virtio" ] ; then
			# Qemu 2.8 is not acception simple "virtio" for some syntaxes
			NicModelSpec=",model=virtio-net"
		else
			NicModelSpec=",model=${NicModel}"
		fi
	else
		if [ "$NicModel" = "virtio" ] ; then
			# Qemu 2.8 is not acception simple "virtio" for some syntaxes
			NicModelSpec="virtio-net"
		else
			NicModelSpec="$NicModel"
		fi
	fi
	if [ "$NicSpec" = "user" ] || [ "$(echo "$NicSpec" | grep -e '^user,')" != "" ] || [ "$(echo "$NicSpec" | grep -e '^user/')" != "" ] || [ "$(echo "$NicSpec" | grep -e '^user:')" != "" ] ; then
		if [ "$(echo "$NetChannel_Value" | grep -e '^user:smb/')" != "" ] ; then
			# Old syntax
			SharedPath="$(echo "$NetChannel_Value" | sed -e 's|^user:smb/|/|g')"
			# ",smbserver=1.2.3.4" can be added to "smb=SharedPath" for a custom host IP in VE. https://www.qemu.org/docs/master/system/invocation.html
			GlobalNetworkSpec="${GlobalNetworkSpec} -device ${DefaultModel},netdev=net${VlanNr} -netdev \"user,id=net${VlanNr},smb=${SharedPath}\""
#			GlobalNetworkSpec="${GlobalNetworkSpec} -device ${DefaultModel},netdev=n${ShortProfileID}${VlanNr} -netdev \"user,id=n${ShortProfileID}${VlanNr},smb=${SharedPath}\""
#			PreviesXarxa=''
#			PosteriorsXarxa=""
			PrefixQemu=''
		else
			SambaOptions="$(printf '%s\n' "$NetChannel_Value" | cut -sf 2 -d '|')"
			if [ "$(printf '%s\n' "$SambaOptions" | grep -e '^smb=')" != "" ] ; then SambaSpec=",${SambaOptions}" ; fi
			UserOptions="$(printf '%s\n' "$NicSpec" | cut -f 1 -d '/' | cut -sf 2- -d ',')"
			if [ "$UserOptions" != "" ] ; then OptionsSpec=",${UserOptions}" ; fi
			if [ "$(ComparaVersions $QemuVersion 2.0)" = "<" ] ; then
				# Old syntax:
				GlobalNetworkSpec="${GlobalNetworkSpec} -net nic${MacSpec}${NicModelSpec}${VlanSpec} -net user${OptionsSpec}${VlanSpec}"
			else
				# New syntax (SMB compatible):
				GlobalNetworkSpec="${GlobalNetworkSpec} -device ${NicModelSpec}${MacSpec},netdev=net${VlanNr} -netdev \"user,id=net${VlanNr}${OptionsSpec}${SambaSpec}\""
#				GlobalNetworkSpec="${GlobalNetworkSpec} -device ${NicModelSpec},netdev=n${ShortProfileID}${VlanNr} -netdev \"user,id=n${ShortProfileID}${VlanNr}${OptionsSpec}${SambaSpec}\""
			fi
			# La part ",rom=/dev/null" no funciona encara a la versió KVM 1.0 per evitar la càrrega de pxe-rtl8139.rom
#			GlobalNetworkSpec="${GlobalNetworkSpec} -net nic${MacSpec},model=rtl8139,rom=/dev/null${VlanSpec} -net user${VlanSpec}"
#			PreviesXarxa=''
#			PosteriorsXarxa=""
#			AmbPrefixSudo=''
			PrefixQemu=''
		fi
	else
		if [ "$NetChannel_Value" = "none" ] || [ "$NetChannel_Value" = "" ] ; then
#			if [ "$NetChannel_Value" = "" ] ; then
				GlobalNetworkSpec="${GlobalNetworkSpec} -net none"
#			else
#				GlobalNetworkSpec="${GlobalNetworkSpec}"
#			fi
#			PreviesXarxa=''
#			PosteriorsXarxa=""
#			AmbPrefixSudo=''
			PrefixQemu=''
		else
			IfConfig="$(WhereProgram ifconfig)"
			if [ "$IfConfig" = "" ] && [ -x /sbin/ifconfig ] ; then IfConfig="/sbin/ifconfig" ; fi
			if [ "$IfConfig" = "" ] && [ -x /bin/ifconfig ] ; then IfConfig="/bin/ifconfig" ; fi
			if [ "$IfConfig" = "" ] && [ -x /usr/sbin/ifconfig ] ; then IfConfig="/usr/sbin/ifconfig" ; fi
			if [ "$IfConfig" = "" ] && [ -x /usr/bin/ifconfig ] ; then IfConfig="/usr/bin/ifconfig" ; fi
			BrCtl="$(WhereProgram brctl)"
			if [ "$BrCtl" = "" ] && [ -x /sbin/brctl ] ; then BrCtl="/sbin/brctl" ; fi
			if [ "$BrCtl" = "" ] && [ -x /bin/brctl ] ; then BrCtl="/bin/brctl" ; fi
			if [ "$BrCtl" = "" ] && [ -x /usr/sbin/brctl ] ; then BrCtl="/usr/sbin/brctl" ; fi
			if [ "$BrCtl" = "" ] && [ -x /usr/bin/brctl ] ; then BrCtl="/usr/bin/brctl" ; fi
			DhClient="$(WhereProgram dhclient)"
			if [ "$DhClient" = "" ] && [ -x /sbin/dhclient ] ; then DhClient="/sbin/dhclient" ; fi
			if [ "$DhClient" = "" ] && [ -x /bin/dhclient ] ; then DhClient="/bin/dhclient" ; fi
			if [ "$DhClient" = "" ] && [ -x /usr/sbin/dhclient ] ; then DhClient="/usr/sbin/dhclient" ; fi
			if [ "$DhClient" = "" ] && [ -x /usr/bin/dhclient ] ; then DhClient="/usr/bin/dhclient" ; fi
			if Is_Executable tunctl || [ "$BrCtl" != "" ] ; then
				ElPont="$(echo "$NicSpec" | cut -sf 3 -d "/")"
				LaTap="tap$(echo "$NicMac" | cut -s -f 4 -d ":")$(echo "$NicMac" | cut -s -f 5 -d ":")$(echo "$NicMac" | cut -s -f 6 -d ":")"
				# La part ",rom=/dev/null" no funciona encara a la versió KVM 1.0 per evitar la càrrega de pxe-rtl8139.rom
				if [ "$(ComparaVersions $QemuVersion 2.0)" = "<" ] ; then
					# -net syntax
					VlanSpec=",vlan=${VlanNr}"
					GlobalNetworkSpec="${GlobalNetworkSpec} -net nic${VlanSpec}${MacSpec}${NicModelSpec} -net tap${VlanSpec},ifname=${LaTap}${SoftwareNicSpec}"
				else
#					if [ "$(ComparaVersions $QemuVersion 3.0)" = "<" ] ; then
						# -netdev syntax
						#VlanSpec=",hubport,hubid=${VlanNr}"
						GlobalNetworkSpec="${GlobalNetworkSpec} -netdev tap,id=vlan${VlanNr}${VlanSpec},ifname=${LaTap}${SoftwareNicSpec} -device ${NicModelSpec},netdev=vlan${VlanNr}${VlanSpec}${MacSpec}"
#					else
#						# -nic syntax
#						GlobalNetworkSpec="${GlobalNetworkSpec} -nic tap,model=${NicModelSpec},ifname=${LaTap}${SoftwareNicSpec}"
#					fi
				fi
				if [ "$ElPont" != "" ] ; then
					if [ "$PreviesXarxa" = "" ] ; then
						# Only write bridge pre&post actions if weren't written before.
						#PontInexistent="$($BrCtl show "$ElPont" 2>&1 | grep -ie "^${ElPont}.*t get info")"
						PontInexistent="$($BrCtl show "$ElPont" 2>&1 | grep -ie "^${ElPont}.*t get info" -ie 'does not exist' -ie 'is not a bridge')"
						MembresPont="$(BridgeMembers "$ElPont")"  # Pot haver quedat un pont orfe de WAN-nic
						if [ "$PontInexistent" != "" ] ; then
							printf '%s\n' "I: Network bridge $ElPont did not exist."
							if [ "$MembresPont" != "" ] ; then
								printf '%s\n' "W: But network bridge $ElPont has NIC members: $(echo $MembresPont)" 1>&2
							fi
						else
							printf '%s\n' "I: Network bridge $ElPont already exists."
							if [ "$MembresPont" != "" ] ; then
								printf '%s\n' "I: Network bridge $ElPont has NIC members: $(echo $MembresPont)"
							else
								printf '%s\n' "I: Network bridge $ElPont had no NIC members."
							fi
						fi
						if [ "$PontInexistent" != "" ] || [ "$MembresPont" = "" ] ; then	# Si no hi havia pont, o aquest és buit i doncs per configurar.
							if [ "$(cat "$ProfileFile" | cut -f 1 -d '#' | grep -e '--wait-wan-nic')" != "" ] ; then
								# NetworkManager dona taants problemes, que cal assegurar-se que hi ha WAN tota l'estona.
								printf '%s\n' "Waiting for a default NIC to network gateway..."
								while [ "$(DefaultNICs)" = "" ] ; do
									sleep 1
								done
								sleep 1
								while [ "$(DefaultNICs)" = "" ] ; do
									sleep 1
								done
							fi
							WanNic="$(DefaultNICs | head -n 1)"
							if [ "$WanNic" != "" ] ; then
								PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}echo \"Detected $WanNic as WAN NIC\"")"
								WanNicEsFisica="$($BrCtl show "$WanNic" 2>&1 | grep -ie "^${WanNic}.*t get info" -ie 'is not a bridge')"
							fi
							if [ "$WanNicEsFisica" != "" ] ; then
								#PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}echo \"$WanNic does not seem a physical interface.\"")"
								printf '%s\n' "I: NIC $WanNic seems to be a physical device."
								NetworkManagerOperant="$(ps -A -o comm | grep -ie '^NetworkManager' -ie '^Network.Manager')"
								if [ "$NetworkManagerOperant" != "" ] ; then
									printf '%s\n' "I: NetworkManager is running. Preparing its stop."
									PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}echo \"Stopping NetworkManager\"")"
									PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}$(RecommendedServiceInvocation stop network-manager)")"
									PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}Result=\$? ; if [ \$ResultN -eq 0 ] ; then ResultN=\$Result ; fi")"
									PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}sleep 1")"
									PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}killall NetworkManager 2>/dev/null")"
									#PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}killall NetworkManager")"
									# Posterior: Reverse lines stack
									PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}#Result=\$? ; if [ \$ResultN -eq 0 ] ; then ResultN=\$Result ; fi" ; printf '%s\n' "$PosteriorsXarxa")"
									PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}#$(RecommendedServiceInvocation start network-manager)" ; printf '%s\n' "$PosteriorsXarxa")"	# No desfarem després el pont per si vàries VM el comparteixen.
									PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}#echo \"Starting back NetworkManager\"" ; printf '%s\n' "$PosteriorsXarxa")"	# No desfarem després el pont per si vàries VM el comparteixen.
								fi
							else
								if [ "$WanNic" != "" ] ; then
									printf '%s\n' "I: NIC $WanNic seems to be a virtual device."
								fi
							fi
							if [ "$PontInexistent" != "" ] ; then
								PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}echo '$' $BrCtl addbr $ElPont")"
								PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}$BrCtl addbr $ElPont")"
								PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}Result=\$? ; if [ \$ResultN -eq 0 ] ; then ResultN=\$Result ; fi")"
							fi
							PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}#Result=\$? ; if [ \$ResultN -eq 0 ] ; then ResultN=\$Result ; fi" ; printf '%s\n' "$PosteriorsXarxa")"
							PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}#$BrCtl delbr $ElPont" ; printf '%s\n' "$PosteriorsXarxa")"	# No eliminarem després el pont per si vàries VM el comparteixen.
							if [ "$WanNicEsFisica" != "" ] && [ "$PontInexistent" != "" ] ; then
								printf '%s\n' "I: Preparing creation of bridge $ElPont and to move WAN NIC $WanNic to it."
								# Si el pont ja existia, potser s'ha creat d'una manera específica i millor no el canviem ni li coloquem la WAN NIC
								CidrNic="$(ip address show dev "$WanNic" | grep -E '(^| )inet .* scope ' | sed -e 's|.*inet |inet |g' | cut -f 2 -d ' ')"
								BroadcastNic="$(ip address show dev "$WanNic" | grep -E '(^| )inet .* brd ' | sed -e 's|.* brd |brd |g' | cut -f 2 -d ' ')"
								DefaultGateway="$(echo $(netstat -rn | grep -e '^0\.0\.0\.0 ') | cut -f 2 -d ' ')"
								ResolvConf="$(cat /etc/resolv.conf 2>/dev/null)"
								if [ "$(echo "$ResolvConf" | grep -e '^nameserver')" = "" ] ; then ResolvConf="" ; fi
								if [ "$(echo "$ResolvConf" | grep -E '^nameserver.*127.0.(0|1).1$')" != "" ] ; then
									ResolvConf="$(echo "$ResolvConf" | grep -vE '^nameserver.*127.0.(0|1).1$')"
									if [ "$(echo "$ResolvConf" | grep -e '^nameserver')" = "" ] ; then
										ResolvConf="$(printf '%s\n' "$ResolvConf" ; printf '%s\n' "# DNS nodes from opennicproject.org" ; printf '%s\n' "nameserver 216.146.35.35" ; printf '%s\n' "nameserver 195.154.226.236")"
									fi
								fi
								Acquirement="$(NicIpAcquirement "$WanNic")"
								if [ "$NetworkManagerOperant" != "" ] ; then
									PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}killall NetworkManager 2>/dev/null")"
								fi
								PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}echo '$' killall dhclient")"
								PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}killall dhclient")"
								if [ "$NetworkManagerOperant" != "" ] ; then PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}killall NetworkManager 2>/dev/null")" ; fi
#								PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}#" ; printf '%s\n' "$PosteriorsXarxa")"	# No desfarem després el pont per si vàries VM el comparteixen.
								if [ "$(printf '%s\n' "$MembresPont" | grep -e "^${WanNic}$")" = "" ] ; then
									PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}$BrCtl delif \"${ElPont}\" \"${WanNic}\" 2>/dev/null")"  # To the case a NIC is already member of bridge.
									PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}echo '$' $BrCtl addif \"${ElPont}\" \"${WanNic}\"")"
									PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}$BrCtl addif \"${ElPont}\" \"${WanNic}\"")"
									PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}Result=\$? ; if [ \$ResultN -eq 0 ] ; then ResultN=\$Result ; fi")"
									PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}#Result=\$? ; if [ \$ResultN -eq 0 ] ; then ResultN=\$Result ; fi" ; printf '%s\n' "$PosteriorsXarxa")"
									PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}#$BrCtl delif \"${ElPont}\" \"${WanNic}\"" ; printf '%s\n' "$PosteriorsXarxa")"	# No desfarem després el pont per si vàries VM el comparteixen.
									PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}#echo '$' $BrCtl delif \"${ElPont}\" \"${WanNic}\"" ; printf '%s\n' "$PosteriorsXarxa")"
									PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}echo \"Not removing WAN NIC $WanNic from bridge ${ElPont} for the case of being shared with other VM.\"" ; printf '%s\n' "$PosteriorsXarxa")"	#do
								fi
								if [ "$NetworkManagerOperant" != "" ] ; then PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}killall NetworkManager 2>/dev/null")" ; fi
								PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}#Result=\$? ; if [ \$ResultN -eq 0 ] ; then ResultN=\$Result ; fi" ; printf '%s\n' "$PosteriorsXarxa")"
								PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}#$IfConfig \"${ElPont}\" down" ; printf '%s\n' "$PosteriorsXarxa")"	# No desfarem després el pont per si vàries VM el comparteixen.
								PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}#echo '$' $IfConfig \"${ElPont}\" down" ; printf '%s\n' "$PosteriorsXarxa")"
								PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}echo \"Not disabling NIC ${ElPont} for the case o being shared with other VM.\"" ; printf '%s\n' "$PosteriorsXarxa")"	#do
								PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}echo '$' $IfConfig \"${WanNic}\" 0.0.0.0")"
								PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}$IfConfig \"${WanNic}\" 0.0.0.0")"
								PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}Result=\$? ; if [ \$ResultN -eq 0 ] ; then ResultN=\$Result ; fi")"
								if [ "$NetworkManagerOperant" != "" ] ; then PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}killall NetworkManager 2>/dev/null")" ; fi
#								PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}#" ; printf '%s\n' "$PosteriorsXarxa")"	# No desfarem després el pont per si vàries VM el comparteixen.
								PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}echo '$' $IfConfig \"${ElPont}\" up")"
								PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}$IfConfig \"${ElPont}\" up")"
								PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}Result=\$? ; if [ \$ResultN -eq 0 ] ; then ResultN=\$Result ; fi")"
								if [ "$Acquirement" = "dhcp" ] ; then
									PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}echo '$' $DhClient \"${ElPont}\"")"
									PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}$DhClient \"${ElPont}\"")"
									PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}Result=\$? ; if [ \$ResultN -eq 0 ] ; then ResultN=\$Result ; fi")"
									if [ "$NetworkManagerOperant" = "" ] ; then
										PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}#Result=\$? ; if [ \$ResultN -eq 0 ] ; then ResultN=\$Result ; fi" ; printf '%s\n' "$PosteriorsXarxa")"
										PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}#$DhClient \"${WanNic}\"" ; printf '%s\n' "$PosteriorsXarxa")"	# No desfarem després el pont per si vàries VM el comparteixen.
										PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}#echo '$' $DhClient \"${WanNic}\"" ; printf '%s\n' "$PosteriorsXarxa")"
										PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}echo \"Not restoring DHCP acquirement to WAN NIC $WanNic  for the case of being used by other VM.\"" ; printf '%s\n' "$PosteriorsXarxa")"	#do
									fi
								else
									if [ "$BroadcastNic" = "" ] ; then
										PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}echo '$' $IfConfig \"${ElPont}\" \"${CidrNic}\"")"
										PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}$IfConfig \"${ElPont}\" \"${CidrNic}\"")"
										PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}Result=\$? ; if [ \$ResultN -eq 0 ] ; then ResultN=\$Result ; fi")"
										if [ "$NetworkManagerOperant" = "" ] ; then
											PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}#Result=\$? ; if [ \$ResultN -eq 0 ] ; then ResultN=\$Result ; fi" ; printf '%s\n' "$PosteriorsXarxa")"
											PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}#$IfConfig \"${WanNic}\" \"${CidrNic}\"" ; printf '%s\n' "$PosteriorsXarxa")"	# No desfarem després el pont per si vàries VM el comparteixen.
											PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}#echo '$' $IfConfig \"${WanNic}\" \"${CidrNic}\"" ; printf '%s\n' "$PosteriorsXarxa")"
											PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}echo \"Not restoring CIDR $CidrNic to WAN NIC $WanNic for the case of being used by other VM.\" \"${}\"" ; printf '%s\n' "$PosteriorsXarxa")"	#do
										fi
									else
										PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}echo '$' $IfConfig \"${ElPont}\" \"${CidrNic}\" broadcast \"${BroadcastNic}\"")"
										PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}$IfConfig \"${ElPont}\" \"${CidrNic}\" broadcast \"${BroadcastNic}\"")"
										PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}Result=\$? ; if [ \$ResultN -eq 0 ] ; then ResultN=\$Result ; fi")"
										if [ "$NetworkManagerOperant" = "" ] ; then
											PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}#Result=\$? ; if [ \$ResultN -eq 0 ] ; then ResultN=\$Result ; fi" ; printf '%s\n' "$PosteriorsXarxa")"
											PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}#$IfConfig \"${WanNic}\" \"${CidrNic}\" broadcast \"${BroadcastNic}\"" ; printf '%s\n' "$PosteriorsXarxa")"	# No desfarem després el pont per si vàries VM el comparteixen.
											PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}#echo '$' $IfConfig \"${WanNic}\" \"${CidrNic}\" broadcast \"${BroadcastNic}\"" ; printf '%s\n' "$PosteriorsXarxa")"
											PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}echo \"Not restoring CIDR $CidrNic to WAN NIC $WanNic for the case of being used by other VM.\"" ; printf '%s\n' "$PosteriorsXarxa")"	#do
										fi
									fi
									PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}echo '$' route add default gw \"${DefaultGateway}\" dev \"${ElPont}\"")"
									PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}route add default gw \"${DefaultGateway}\" dev \"${ElPont}\"")"
									PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}Result=\$? ; if [ \$ResultN -eq 0 ] ; then ResultN=\$Result ; fi")"
									if [ "$NetworkManagerOperant" = "" ] ; then
										PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}#Result=\$? ; if [ \$ResultN -eq 0 ] ; then ResultN=\$Result ; fi" ; printf '%s\n' "$PosteriorsXarxa")"
										PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}#route add default gw \"${DefaultGateway}\" dev \"${WanNic}\"" ; printf '%s\n' "$PosteriorsXarxa")"	# No desfarem després el pont per si vàries VM el comparteixen.
										PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}#echo '$' route add default gw \"${DefaultGateway}\" dev \"${WanNic}\"" ; printf '%s\n' "$PosteriorsXarxa")"
										PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}echo \"Not restoring default gateway $DefaultGateway to WAN NIC $WanNic for the case of being used by other VM.\"" ; printf '%s\n' "$PosteriorsXarxa")"	#do
									fi
								fi
								if [ "$ResolvConf" != "" ] && [ -f /etc/resolvconf/resolv.conf.d/base ] ; then
									# Lidiar amb el servei resolvconf que descarta DNS quan no venen d'un gestor de xarxa (nm/ifupdown)
									if [ "$(cat /etc/resolvconf/resolv.conf.d/base | grep -e '^nameserver')" = "" ] ; then
										if [ ! -f /etc/resolvconf/resolv.conf.d/base.bak ] ; then
											PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}echo '$' cp -a /etc/resolvconf/resolv.conf.d/base /etc/resolvconf/resolv.conf.d/base.bak")"
											PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}cp -a /etc/resolvconf/resolv.conf.d/base /etc/resolvconf/resolv.conf.d/base.bak")"
											PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}Result=\$? ; if [ \$ResultN -eq 0 ] ; then ResultN=\$Result ; fi")"
											PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}#Result=\$? ; if [ \$ResultN -eq 0 ] ; then ResultN=\$Result ; fi" ; printf '%s\n' "$PosteriorsXarxa")"
											PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}#mv /etc/resolvconf/resolv.conf.d/base.bak /etc/resolvconf/resolv.conf.d/base" ; printf '%s\n' "$PosteriorsXarxa")"	# No desfarem després el pont per si vàries VM el comparteixen.
											PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}#echo '$' mv /etc/resolvconf/resolv.conf.d/base.bak /etc/resolvconf/resolv.conf.d/base" ; printf '%s\n' "$PosteriorsXarxa")"
											PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}echo \"Not restoring old /etc/resolvconf/resolv.conf.d/base for the case of being used by other VM.\"" ; printf '%s\n' "$PosteriorsXarxa")"	#do
										fi
										PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}echo \"${ResolvConf}\" | grep -E \"^(nameserver|search|#.*opennicproject)\" >> /etc/resolvconf/resolv.conf.d/base")"
										PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}Result=\$? ; if [ \$ResultN -eq 0 ] ; then ResultN=\$Result ; fi")"
#										PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}#" ; printf '%s\n' "$PosteriorsXarxa")"	# No desfarem després el pont per si vàries VM el comparteixen.
										PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}echo \"${ResolvConf}\" > /etc/resolv.conf")"
#										PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}#" ; printf '%s\n' "$PosteriorsXarxa")"	# No desfarem després el pont per si vàries VM el comparteixen.
									fi
								fi
							else
								if [ "$PontInexistent" = "" ] ; then
									printf '%s\n' "I: Not moving WAN NIC $WanNic to bridge $ElPont because bridge was already configured."
								else
									# WanNicEsFisica==""
									printf '%s\n' "I: Not moving WAN NIC $WanNic to bridge $ElPont because it's a virtual network device."
								fi
							fi
						else
							printf '%s\n' "I: Not re/configuring bridge $ElPont because it's already being used by some NIC."
						fi
					fi
					# Perhaps tunctl can only assign owner if it's run as root.
					PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}echo '$' tunctl -u $(whoami) -g kvm -t $LaTap")"
					PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}tunctl -u $(whoami) -g kvm -t $LaTap")"
					PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}Result=\$? ; if [ \$ResultN -eq 0 ] ; then ResultN=\$Result ; fi")"
					PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}Result=\$? ; if [ \$ResultN -eq 0 ] ; then ResultN=\$Result ; fi" ; printf '%s\n' "$PosteriorsXarxa")"
					PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}tunctl -d $LaTap" ; printf '%s\n' "$PosteriorsXarxa")"
					PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}echo '$' tunctl -d $LaTap" ; printf '%s\n' "$PosteriorsXarxa")"
					PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}$BrCtl delif $ElPont $LaTap 2>/dev/null")"
					PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}echo '$' $BrCtl addif $ElPont $LaTap")"
					PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}$BrCtl addif $ElPont $LaTap")"
					PreviesXarxa="$(printf '%s\n' "$PreviesXarxa" ; printf '%s\n' "${IdentacioXarxa}Result=\$? ; if [ \$ResultN -eq 0 ] ; then ResultN=\$Result ; fi")"
					PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}Result=\$? ; if [ \$ResultN -eq 0 ] ; then ResultN=\$Result ; fi" ; printf '%s\n' "$PosteriorsXarxa")"
					PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}$BrCtl delif $ElPont $LaTap" ; printf '%s\n' "$PosteriorsXarxa")"
					PosteriorsXarxa="$(printf '%s\n' "${IdentacioXarxa}echo '$' $BrCtl delif $ElPont $LaTap" ; printf '%s\n' "$PosteriorsXarxa")"
				fi
				#Encara no hem aconseguit que l'usuari normal pugui utilitzar /dev/net/tun
				#Encara Qemu ha de ser executat com a "root" per unir-se a la xarxa real.
				PrefixQemu=''
			else
				MissatgeSincron "$(printf '%s\n' "PROBLEMA: No s'ha trobat el configurador de xarxa tunctl o brctl" ; printf '%s\n' "SOLUCIO: instalar els paquets bridge-utils i uml-utilities")"	#'
				Result=54 ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
			fi
		fi
	fi
}

RecommendedServiceInvocation ()
# Syntax example: RecommendedServiceInvocation start lightdm
{
	local Action="$1"
	if [ $# -gt 0 ] ; then shift ; fi
	local ServiceName="$1"
	local Option="$Action"
	local Value=""
	
	case "$Option" in
		"start" ) Option="start-stop" ;;
		"stop" ) Option="start-stop" ;;
		"restart" ) Option="start-stop" ;;
		"reload" ) Option="start-stop" ;;
	esac
	case "$Option" in
		"start-stop" )
			if [ "$InitProfilesDir" != "" ] ; then
				case "$InitSoftware" in
					"systemd" )
						Value="systemctl $Action $ServiceName"
						;;
					"upstart" )
						Value="initctl $Action $ServiceName"
						;;
					* ) Value="${ServicePrefix}${ServiceName} $Action" ;;
				esac
			else
				Value="${ServicePrefix}${ServiceName} $Action"
			fi
			;;
	esac
	if [ "$Value" != "" ] ; then printf '%s\n' "$Value" ; fi
}

Configuracio ()
{	local ValorBuit="@@@"
	local ValorTmp=""
	local ValorTmp2=""
	local NicMac=""
	local LaTap=""
	local ElPont=""
	local UnitatsOptiques=""
	local MemoryQuotaMiB_Min=0
	local MemoryQuotaMiB_Max=0
	local FreeVncPort=0
	local IdentacioXarxa="	"
	local DefaultHostCache='cache=writethrough'
	local CurHostCache=''
	local NewMacSpec=''
	local Cur_Is_OpticalMedia=254
	local Boot_Is_OpticalMedia=254
	local Result=0
	local ResultN=0
	
	if [ ! -d "$DirTemp" ] ; then DirTemp="/run/shm" ; fi
	if [ ! -d "$DirTemp" ] ; then DirTemp="/tmp" ; fi
	SSD="start-stop-daemon"
	if ! Is_Executable "$SSD" && Is_Executable /sbin/start-stop-daemon ; then SSD="/sbin/start-stop-daemon" ; fi
	InitSoftware=""
	if Is_Executable /bin/systemctl || Is_Executable systemctl ; then
		# [ "$(ls /run/systemd/ 2>/dev/null)" != "" ]	Condition could not work in a chroot
		InitSoftware="systemd"
	else
		if Is_Executable /sbin/initctl || Is_Executable initctl ; then
			# (All GNU operating systems with Upstart have replaced it by systemd later)
			# Used by default in Ubuntu from version 6.10 to version 14.10
			# Used by default in Fedora from version 9 to version 14
			# Used by default in RHEL 6 (Red Hat, CentOS, Scientific Linux, Oracle Linux)
			# Used by default in Maemo 5 and MeeGo
			InitSoftware="upstart"
		else
			if Is_Executable /sbin/insserv || Is_Executable insserv || Is_Executable /usr/sbin/update-rc.d || Is_Executable update-rc.d || Is_Executable chkconfig ; then
				# insserv seems to be the LSB-compliant tool for System-V
				CurrentFile="$(WhereProgram /sbin/runlevel)"
				if [ "$CurrentFile" = "" ] ; then CurrentFile="$(WhereProgram runlevel)" ; fi
				if [ "$CurrentFile" != "" ] ; then
					if [ "$("$CurrentFile" --version 2>/dev/null | grep -ie upstart)" = "" ] ; then
						InitSoftware="systemv"
					else
						InitSoftware="upstart"
					fi
				fi
			else
				if [ -f /etc/inittab ] ; then
					# System-V
					InitSoftware="systemv"
				else
					InitSoftware=""
				fi
			fi
		fi
	fi
	InitProfilesDir=""
	case "$InitSoftware" in
		"systemd" )
			if [ -d "/etc/systemd/system" ] ; then
				InitProfilesDir="/etc/systemd/system"
			fi
			ServicePrefix=""
			;;
		"upstart" )
			if [ -d /etc/init ] ; then
				# Directory present in Ubuntu from version 9.10 to version 16.04 or more (with and without Upstart)
				InitProfilesDir="/etc/init"
			fi
			ServicePrefix=""
			if [ ! -f "/etc/init/${ServiceName}.conf" ] ; then
				if Is_Executable /sbin/insserv || Is_Executable insserv || Is_Executable /usr/sbin/update-rc.d || Is_Executable update-rc.d || Is_Executable chkconfig ; then
					if Is_Executable /sbin/runlevel || Is_Executable runlevel ; then
						if [ -x "/etc/init.d/${ServiceName}" ] || [ -x "/etc/rc.d/init.d/${ServiceName}" ] ; then
							# Let's use SystemV compatibility layer; it can be an upgraded environment from SystemV to Systemd
							if Is_Executable service ; then
								ServicePrefix="service "
							else
								if Is_Executable invoke-rc.d ; then
									ServicePrefix="invoke-rc.d "
								fi
							fi
						fi
					fi
				fi
			fi
			;;
		"systemv" )
			InitProfilesDir="" # System-V does not use job profile files
			# Must be useful for any action (install|--help|etc)
			if Is_Executable service ; then
				ServicePrefix="service "
			else
				if Is_Executable invoke-rc.d ; then
					ServicePrefix="invoke-rc.d "
				fi
			fi
			;;
		* )
			# Must be useful for any action (install|--help|etc)
			if Is_Executable service ; then
				ServicePrefix="service "
			else
				if Is_Executable invoke-rc.d ; then
					ServicePrefix="invoke-rc.d "
				fi
			fi
			;;
	esac
	InitToolForStartStop="$ServicePrefix"
	if [ "$InitToolForStartStop" = "" ] && [ "$InitSoftware" = "systemd" ] ; then InitToolForStartStop="systemctl" ; fi
	if [ "$InitToolForStartStop" = "" ] && [ "$InitSoftware" = "upstart" ] ; then InitToolForStartStop="initctl" ; fi
	UnitatsOptiques="$(UnidadesOpticas)"
	# If modprobing kvm succeeds, but modprobing kvm-intel or kvm-amd fails (but /proc/cpuinfo claims that hardware acceleration is supported), check your BIOS settings. Some vendors (especially laptop vendors) disable these processor extensions by default. To determine whether there's no hardware support or there is but the extensions are disabled in BIOS, the output from dmesg after having failed to modprobe will tell.
	HostVirtualitza="$(cat /proc/cpuinfo | grep -wie "flags" | grep -woie "svm" -woie "vmx")"
#	SistemaVirtualitza="$(lsmod | grep -iE "^kvm_[[:blank:]]")"
	SistemaVirtualitza="$(lsmod | tr -s '\t' ' ' | grep -ie '^kvm_' -ie '^kvm ')"
	if [ "$(echo "$BootMedia" | grep -ie '\.conf$')" != "" ] ; then
		# Conversió de fitxer .conf antic, si no existeix el nou .matromu
		if [ "$(cat "$BootMedia" | grep -ie '^BootMedia=')" != "" ] ; then
			ValorTmp="$(echo "$BootMedia" | sed -e 's/\.conf$/\.matromu/g')"
			if [ ! -f "$ValorTmp" ] ; then
				mv "$BootMedia" "$ValorTmp"
				BootMedia="$ValorTmp"
			fi
		fi
	fi
	NomSimpleImatge="$(dirname "$(basename "$BootMedia" | tr -s "." "/")" | tr -s "/" "." | sed -e "s/^\.$/$(basename "$BootMedia")/g")"
	ExtensioImatge1="$(echo "$BootMedia" | cut -s -f 2- -d '.' | sed -e "s/\./\n/g" | tail --lines=1)"
	if [ "$(echo "$BootMedia" | grep -e '.\..' )" = "" ] ; then ExtensioImatge1='' ; fi
	if [ ! -b "$BootMedia" ] ; then
		DirectoriBase="$(dirname "$BootMedia")"
	else
		DirectoriBase="$HOME"
	fi
	if [ "$ExtensioImatge1" = "matromu" ] || [ "$ExtensioImatge1" = "conf" ] ; then
		# Setting true profile filename
		ProfileFile="$BootMedia"
		if [ ! -f "$ProfileFile" ] ; then
			touch "$ProfileFile" 2>/dev/null
			Result=$?
			if [ $Result -ne 0 ] ; then
				InformarEsdeveniment "Advertencia: Se asume la configuracion por defecto. No se puede crear el fichero $ProfileFile" 1>&2
			fi
		fi
	else
		# Setting true profile filename
		ProfileFile="${DirectoriBase}/${NomSimpleImatge}.matromu"
		if [ -f "${DirectoriBase}/${NomSimpleImatge}.conf" ] && [ ! -f "${DirectoriBase}/${NomSimpleImatge}.matromu" ] ; then
			# Conversió de fitxer .conf antic, si no existeix el nou .matromu
			if [ "$(cat "${DirectoriBase}/${NomSimpleImatge}.conf" | grep -ie '^BootMedia=')" != "" ] ; then
				mv "${DirectoriBase}/${NomSimpleImatge}.conf" "${DirectoriBase}/${NomSimpleImatge}.matromu"
			fi
		fi
		if [ "$(echo "$ProfileFile" | grep -E '(^/dev/|^/proc/|^/run|^/var/run/|^/sys/)')" != "" ] && [ ! -f "$ProfileFile" ] ; then
			# En lugar de una zona de dispositivos o similar, lo creamos en $HOME de forma predeterminada.
			DirectoriBase="$HOME"
			ProfileFile="${DirectoriBase}/$(basename "$ProfileFile")"
		fi
	fi
	# Early getting ProfileArchitecture before saving its value later in the file, with the purpose of setting and use QemuBin.
#	ProfileArchitecture="$(ValorVariableFichero "$ProfileFile" Architecture "")"
	ProfileArchitecture="$(IniVarValue "$ProfileFile" Architecture '' "" '=')"
#	if [ "$ProfileArchitecture" = "" ] ; then ProfileArchitecture="$(ValorVariableFichero "$ProfileFile" TipusPlataforma "")" ; fi
	if [ "$ProfileArchitecture" = "" ] ; then ProfileArchitecture="$(IniVarValue "$ProfileFile" TipusPlataforma '' "" '=')" ; fi
	QemuBin="$(GetQemuBin "$ProfileArchitecture")"
	if [ "$ExtensioImatge1" = "matromu" ] || [ "$ExtensioImatge1" = "conf" ] ; then
		# Continuing with setting true boot media
		BootMedia="$(GetSetRenamedParameter "$ProfileFile" "DiscArrencada" "BootMedia" '""' "# BootMedia: Fichero-imagen de disco con sistema operativo" 2>/dev/null)"
		if [ "$(echo "$BootMedia" | grep -ie '^file://')" != "" ] ; then
			BootMedia="$(echo "$BootMedia" | cut -c 8-)"
		fi
	else
		# Continuing with setting true boot media
#		ValorTmp="$(ValorVariableFichero "$ProfileFile" "BootMedia" "")"
		ValorTmp="$(IniVarValue "$ProfileFile" BootMedia '' "" '=')"
		ValorTmp="$(basename "$ValorTmp")"
#		ValorTmp2="$(ValorVariableFichero "$ProfileFile" "Media2" "")"
		ValorTmp2="$(IniVarValue "$ProfileFile" Media2 '' "" '=')"
		ValorTmp2="$(basename "$ValorTmp2")"
		if [ "$ValorTmp" != "$(basename "$BootMedia")" ] && [ "$ValorTmp2" != "$(basename "$BootMedia")" ] ; then
			if [ "$(dirname "$ProfileFile")" = "$(dirname "$BootMedia")" ] ; then
#				ModificarParametreConf "$ProfileFile" "BootMedia" "\"$(basename "$BootMedia")\"" 2>/dev/null
				SetIniVarValue "$ProfileFile" BootMedia '' "\"$(basename "$BootMedia")\"" '=' "" 2>/dev/null
			else
#				ModificarParametreConf "$ProfileFile" "BootMedia" "\"$BootMedia\"" 2>/dev/null
				SetIniVarValue "$ProfileFile" BootMedia '' "\"$BootMedia\"" '=' "" 2>/dev/null
			fi
		fi
	fi
	if [ "$(echo "$ProfileFile" | grep -e '^/')" = "" ] && [ -d "$(dirname "$ProfileFile")" ] ; then
		# Conversió a ruta absoluta
		PreviDir="$(pwd)"
		cd "$(dirname "$ProfileFile")"
		ProfileFile="$(pwd)/$(basename "$ProfileFile")"
		ProfileFile="$(echo "$ProfileFile" | tr -s '/')"
		cd "$PreviDir"
	fi
#	if [ "$(echo "$BootMedia" | grep -e '^".*"$')" != "" ] ; then
#		# Eliminació de cometes d'inici i fi, trobades quan hi ha error en llegir o escriure el fitxer de perfil.
#		BootMedia="$(echo "$BootMedia" | sed -e 's|^\"||g' | sed -e 's|\"$||g')"
#	fi

	ValorTmp="# Media2: Fichero-imagen de disco adicional a anexar o crear como secundario;"
	ValorTmp="$(echo "$ValorTmp" ; echo "# como alternativa 'Media' se puede especificar un dispositivo fisico como /dev/sr0 o /dev/sdb")"
	Media2="$(GetSetRenamedParameter "$ProfileFile" "DiscAddicional" "Media2" "\"\"" "\n$ValorTmp" 2>/dev/null)"	#'
	if [ "$(echo "$Media2" | grep -ie '^file://')" != "" ] ; then
		Media2="$(echo "$Media2" | cut -c 8-)"
	fi
#	if [ "$(echo "$Media2" | grep -e '^".*"$')" != "" ] ; then
#		# Eliminació de cometes d'inici i fi, trobades quan hi ha error en llegir o escriure el fitxer de perfil.
#		Media2="$(echo "$Media2" | sed -e 's|^\"||g' | sed -e 's|\"$||g')"
#	fi

	MediaPersistence=1
	MediaPersistence="$(GetSetRenamedParameter "$ProfileFile" "Persistencia" "MediaPersistence" "$MediaPersistence" "\n# MediaPersistence: 1 para que se conserven los cambios a disco; 0 para que al finalizar la ejecucion quede todo como estaba." 2>/dev/null)"
	
#	SessioEscriptori="$(ps -A -o comm | grep -E "^(lightdm|gdm|kdm|ldm|xdm)" | grep -ve "kdmflush")"
	SessioEscriptori="$DISPLAY"
#	DisplayChannels="$(ValorVariableFichero "$ProfileFile" DisplayChannels '')"	# Preliminar read; only to detect curses specification
	DisplayChannels="$(IniVarValue "$ProfileFile" DisplayChannels '' "" '=')"	# Preliminar read; only to detect curses specification
#	ExtraParameters="$(ValorVariableFichero "$ProfileFile" ExtraParameters '')"	# Preliminar read; only to detect curses or boot specifications
	ExtraParameters="$(IniVarValue "$ProfileFile" ExtraParameters '' "" '=')"	# Preliminar read; only to detect curses or boot specifications
	if [ "$(echo ",${DisplayChannels}," | grep -ie ",curses,")" != "" ] || [ "$(StringWithParameters "$ExtraParameters" '-curses' '-display curses')" != "" ] ; then
		SessioEscriptori=""
	fi
	CurHostCache="$(StringWithParameters "$ExtraParameters" "cache")"
	if [ "$CurHostCache" = "" ] ; then
		if [ "$MediaPersistence" = "0" ] ; then
			CurHostCache='cache=unsafe'
		else
			CurHostCache="$DefaultHostCache"
		fi
	else
		ExtraParameters="$(StringWithoutParameter "$ExtraParameters" "cache")"
	fi
	VirtualSsdSupported="$("$QemuBin" -device ? 2>&1 | grep -e '"virtio-scsi"')"
	if [ "$VirtualSsdSupported" != "" ] ; then
		VirtualSsdDiskSpecification=",discard=unmap,detect-zeroes=unmap"
	fi
	if [ -b "$BootMedia" ] ; then
		# No es un fichero, sino un dispositivo (de bloque).
		ValorTmp="$(echo "$BootMedia" | cut -f 3- -d '/')"
		if [ "$(StringWithParameters "$ExtraParameters" "-boot")" = "" ] ; then
			if [ "$(echo " $UnitatsOptiques " | grep -e " $ValorTmp ")" != "" ] ; then
				ParametresDisc=" -boot dc -drive \"file=${BootMedia},media=cdrom,index=0\""
			else
				ParametresDisc=" -boot cd -drive \"file=${BootMedia},media=disk${VirtualSsdDiskSpecification},index=0,${CurHostCache}\""
			fi
		else
			if [ "$(echo " $UnitatsOptiques " | grep -e " $ValorTmp ")" != "" ] ; then
				ParametresDisc=" -drive \"file=${BootMedia},media=cdrom,index=0\""
			else
				ParametresDisc=" -drive \"file=${BootMedia},media=disk${VirtualSsdDiskSpecification},index=0,${CurHostCache}\""
			fi
		fi
	else
		ExtensioImatge1="$(echo "$BootMedia" | cut -s -f 2- -d '.' | sed -e "s/\./\n/g" | tail --lines=1)"
		if [ "$BootMedia" != "" ] ; then
			Is_OpticalMedia "$BootMedia"
			Cur_Is_OpticalMedia=$?
			if [ ! -e "$BootMedia" ] && [ "$ExtensioImatge1" != "matromu" ] && [ "$ExtensioImatge1" != "conf" ] && [ $Cur_Is_OpticalMedia -ne 0 ] ; then
				PreguntarCrearDisco "$BootMedia"
			fi
			if [ -e "$BootMedia" ] ; then
				if [ "$(StringWithParameters "$ExtraParameters" "-boot")" = "" ] ; then
					if [ $Cur_Is_OpticalMedia -eq 0 ] ; then
						Boot_Is_OpticalMedia=0
						#ParametresDisc=" -boot d -cdrom \"$BootMedia\""
						ParametresDisc=" -boot dc -drive \"file=${BootMedia},media=cdrom,index=0\""
					else
						#ParametresDisc=" -boot c -hda \"$BootMedia\""
						ParametresDisc=" -boot cd -drive \"file=${BootMedia},media=disk${VirtualSsdDiskSpecification},index=0,${CurHostCache}\""
					fi
				else
					if [ $Cur_Is_OpticalMedia -eq 0 ] ; then
						Boot_Is_OpticalMedia=0
						ParametresDisc=" -drive \"file=${BootMedia},media=cdrom,index=0\""
					else
						ParametresDisc=" -drive \"file=${BootMedia},media=disk${VirtualSsdDiskSpecification},index=0,${CurHostCache}\""
					fi
				fi
			fi
		fi
	fi
	
	if [ -b "$Media2" ] ; then
		# No es un fichero, sino un dispositivo (de bloque).
		ValorTmp="$(echo "$Media2" | cut -f 3- -d '/')"
		if [ "$(echo " $UnitatsOptiques " | grep -e " $ValorTmp ")" != "" ] ; then
			ParametresDisc="$ParametresDisc -drive \"file=${Media2},media=cdrom,index=1\""
		else
			ParametresDisc="$ParametresDisc -drive \"file=${Media2},media=disk${VirtualSsdDiskSpecification},index=1,${CurHostCache}\""
		fi
		if [ "$(echo "$ProfileFile" | grep -E '(^/dev/|^/proc/|^/run|^/var/run/|^/sys/)')" != "" ] ; then
			# Si el perfil de configuración se creó en una zona de dispositivos o similar, lo movemos a $HOME
			mv "$ProfileFile" "$HOME"/
			ProfileFile="${HOME}/$(basename "$ProfileFile")"
		fi
	else
		ExtensioImatge2="$(echo "$Media2" | cut -s -f 2- -d '.' | sed -e "s/\./\n/g" | tail --lines=1)"
		Is_OpticalMedia "$Media2"
		Cur_Is_OpticalMedia=$?
		if [ "$Media2" != "" ] ; then
			if [ ! -e "$Media2" ] && [ "$ExtensioImatge2" != "matromu" ] && [ "$ExtensioImatge2" != "conf" ] && [ $Cur_Is_OpticalMedia -ne 0 ] ; then
				PreguntarCrearDisco "$Media2"
			fi
			if [ -f "$Media2" ] ; then
				if [ $Cur_Is_OpticalMedia -eq 0 ] ; then
					#ParametresDisc="$ParametresDisc -cdrom \"$Media2\""
					ParametresDisc="$ParametresDisc -drive \"file=${Media2},media=cdrom,index=1\""
				else
					#ParametresDisc="$ParametresDisc -hdb \"$Media2\""
					ParametresDisc="$ParametresDisc -drive \"file=${Media2},media=disk${VirtualSsdDiskSpecification},index=1,${CurHostCache}\""
				fi
			fi
		fi
	fi
	if [ "$VirtualSsdSupported" != "" ] && [ "$(printf '%s\n' "$ParametresDisc" | grep -e 'media=disk')" != "" ] ; then
		ParametresDisc="-device virtio-scsi $ParametresDisc"
	fi
	
	BitacoraPerfil="$(dirname "$(basename "$ProfileFile" | tr -s "." "/")" | tr -s "/" "." | sed -e "s/^\.$/$(basename "$RutaFitxer")/g")"
	BitacoraPerfil="$(dirname "$dirname")/${BitacoraPerfil}.log"
	#Ara serà acumulativa
	#rm -f "$BitacoraPerfil"
	if [ -f "$BitacoraPerfil" ] ; then
		echo '' 2>/dev/null >> "$BitacoraPerfil"
	fi
	
	#ProfileID="$(GetSetRenamedParameter "$ProfileFile" "Identificador" "ProfileIdentifier" "\"${NomSimpleImatge}\"" "\n# ProfileIdentifier: Nombre unico para el control de ejecucion" 2>/dev/null)"
	ProfileID="$(echo "$ProfileFile" | md5sum | cut -f 1 -d ' ')"
	ShortProfileID="$(echo "$ProfileID" | sed -e 's|[0-9]||g')"
	if [ ! -d "${DirTemp}/matromu" ] ; then
		rm -f "${DirTemp}/matromu"
		mkdir -p "${DirTemp}/matromu"
		chmod a+rwX "${DirTemp}/matromu"
	fi
	ProfileTemp="${DirTemp}/matromu/${ProfileID}"
	RunID=""
	if [ -f "${DirectoriBase}/${ProfileID}.lock" ] ; then
#		RunID="$(ValorVariableFichero "${DirectoriBase}/${ProfileID}.lock" "$RunID" "")"
		RunID="$(IniVarValue "${DirectoriBase}/${ProfileID}.lock" "$RunID" '' "" '=')"
	fi
	if [ "$RunID" = "" ] ; then RunID="$$" ; fi
#		RunID="$(date +'%Y%m%d.%H%M%S.%N').$(dd if=/dev/urandom count=1 2> /dev/null | cksum | cut -f1 -d" " )"
#	fi
	
	HandyName="$(GetSetRenamedParameter "$ProfileFile" "TitolFinestra" "HandyName" "\"${NomSimpleImatge}\"" "\n# HandyName: Titulo/etiqueta para la visualizacion en pantalla" 2>/dev/null)"
	
	InformarEsdeveniment "[${ShortProfileID}/${RunID}] ID $ProfileID Short: ${ShortProfileID} RunID: $RunID HandyName: $HandyName ProfileFile: $ProfileFile"
	
	ValorTmp="# MemoryQuotaMiB: Memoria RAM para la maquina virtual; sintaxis admitidas:"
	ValorTmp="$(echo "$ValorTmp" ; echo "#	Numero de MiB")"	#'
	ValorTmp="$(echo "$ValorTmp" ; echo "#	0 para asignar automaticamente segun disponibilidad en el inicio (1/2 de RAM libre)")"	#'
	ValorTmp="$(echo "$ValorTmp" ; echo "#	una franja (como 32-512) para asignar automaticamente pero dentro de los limites.")"
	MemoryQuotaMiB="$(GetSetRenamedParameter "$ProfileFile" "MemoriaDedicadaMiB" "MemoryQuotaMiB" "0" "\n$ValorTmp" 2>/dev/null)"
	MemoryQuotaMiB_Min=$(echo "$MemoryQuotaMiB" | cut -f 1 -d '-')
	if [ "$MemoryQuotaMiB_Min" = "" ] ; then MemoryQuotaMiB_Min=0 ; fi
	MemoryQuotaMiB_Max=$(echo "$MemoryQuotaMiB" | cut -f 2 -d '-')
	if [ "$MemoryQuotaMiB_Max" = "" ] ; then MemoryQuotaMiB_Max=0 ; fi
	if [ $LimiteMemoriaQemu -ne 0 ] ; then
		if [ $MemoryQuotaMiB_Min -gt $LimiteMemoriaQemu ] || [ $MemoryQuotaMiB_Max -gt $LimiteMemoriaQemu ] ; then
			InformarEsdeveniment "[${ShortProfileID}/${RunID}] ADVERTENCIA: Una cantidad de memoria especificada ($MemoryQuotaMiB) excede el maximo de Qemu ($LimiteMemoriaQemu MiB)"
			KeepProfileLogs="1"
			if [ $MemoryQuotaMiB_Min -gt $LimiteMemoriaQemu ] ; then
				MemoryQuotaMiB_Min=$LimiteMemoriaQemu
			fi
			if [ $MemoryQuotaMiB_Max -gt $LimiteMemoriaQemu ] ; then
				MemoryQuotaMiB_Max=$LimiteMemoriaQemu
			fi
		fi
	fi
	if [ "$MemoryQuotaMiB" = "0" ] || [ "$(printf '%s\n' "$MemoryQuotaMiB" | grep -e '-')" != "" ] ; then
		# Si s'especifica 0, s'utilitza la meitat de RAM disponible al moment.
		ValorTmp=$(MemoriaRamDisponible -m)
		ValorTmp=$(($ValorTmp / 2))
		if [ $ValorTmp -gt $LimiteMemoriaQemu ] && [ $LimiteMemoriaQemu -ne 0 ] ; then
			ValorTmp=$LimiteMemoriaQemu
		fi
		if [ "$MemoryQuotaMiB" != "0" ] ; then
			if [ $ValorTmp -lt $MemoryQuotaMiB_Min ] ; then
				ValorTmp=$MemoryQuotaMiB_Min
			fi
			if [ $ValorTmp -gt $MemoryQuotaMiB_Max ] && [ "$MemoryQuotaMiB_Max" != "0" ] ; then
				ValorTmp=$MemoryQuotaMiB_Max
			fi
		fi
		MemoryQuotaMiB=$ValorTmp
	fi
	
	FreeVncPort=5901
	while [ "$(env LANG=en netstat -tln | grep -ie "^tcp.*:${FreeVncPort} .* LISTEN")" != "" ] ; do
		FreeVncPort=$(($FreeVncPort + 1))
		if [ $FreeVncPort -gt 65535 ] ; then
			FreeVncPort=1025
		fi
	done
	if [ "$SessioEscriptori" = "" ] ; then
		DisplayChannels="vnc::${FreeVncPort}"
	else
		if ! Is_Executable vncviewer || [ $Boot_Is_OpticalMedia -eq 0 ] ; then
			# En SDL s'escala la imatge en maximitzar, en VNCd no.
			# Com que qui virtualitza CDs és el tècnic, no hi ha problema amb SDL predeterminat.
			DisplayChannels="sdl"
		else
			DisplayChannels="vnc"
		fi
	fi
	ValorTmp="# DisplayChannels: sdl,vnc:port,vnci,curses o una combinacion compatible entre comas."
	ValorTmp="$(echo "$ValorTmp" ; echo "# 	sdl		Simple DirectMedia Layer (VGA local)")"
	ValorTmp="$(echo "$ValorTmp" ; echo "# 	sdl:opciones	SDL 'opciones' puede ser: noframe (sin marcos de ventana) noquit (sin cierre de ventana) fullscreen (a pantalla completa)")"
	ValorTmp="$(echo "$ValorTmp" ; echo "# 	vnc		VNC directo en el primer puerto disponible (5900+); incompatible con 'vnci'; se lanza visor en sesion de escritorio.")"
	ValorTmp="$(echo "$ValorTmp" ; echo "# 	vnc::port:pwd	VNC que espere en el puerto 'port' y (opcionalmente) con contraseña 'pwd'; incompatible con 'vnci'")"
	ValorTmp="$(echo "$ValorTmp" ; echo "# 	vnci		VNC inverso al equipo local (incompatible con 'vnc')")"
	ValorTmp="$(echo "$ValorTmp" ; echo "# 	vnci:host:port	VNC inverso al equipo:puerto especificados como host:port (incompatible con 'vnc')")"
	ValorTmp="$(echo "$ValorTmp" ; echo "# 	curses		Modos texto al terminal de ejecucion")"
	ValorTmp="$(echo "$ValorTmp" ; echo "# 	none		Sin adaptador grafico ni visualizacion (no combinable)")"
	DisplayChannels="$(GetSetRenamedParameter "$ProfileFile" "ConnexioVisual" "DisplayChannels" "\"${DisplayChannels}\"" "\n$ValorTmp" 2>/dev/null)"
	if [ "$(echo ",${DisplayChannels}," | grep -ie ",sdl,")$(echo ",${DisplayChannels}," | grep -ie ",sdl:")$(echo ",${DisplayChannels}," | grep -ie ",gtk,")$(echo ",${DisplayChannels}," | grep -ie ",gtk:")" != "" ] ; then
		VisioSDL="1"
	fi
	VncPassword=""
	if [ "$(printf '%s' ",${DisplayChannels}," | grep -ie ',vnci:' -ie ',vnci,')" != "" ] ; then
		VnciSpecification="$(printf '%s' ",${DisplayChannels}," | sed -e 's|.*,vnci:|vnci:|gi' -e 's|.*,vnci,|vnci,|gi' | grep -ie '^vnci:' -ie '^vnci,' | head -n 1 | cut -f 1 -d ',')"
		VisioVncInvers="1"
		VnciHost="$(printf '%s' "$VnciSpecification" | cut -sf 2 -d ':')"
		if [ "$VnciHost" = "" ] ; then
			VnciHost="127.0.0.1"
		fi
		VnciPort="$(printf '%s' "$VnciSpecification" | cut -sf 3 -d ':')"
		if ! Is_IntegerNr $VnciPort ; then
#			VnciPort="$(ValorVariableFichero "$ProfileFile" VncPort "5500")"
			VnciPort="$(IniVarValue "$ProfileFile" VncPort '' "5500" '=')"
		fi
		# AVIS: Amb QEMU 2.0.0 i RealVNC(vncviewer) 4.1.1 no funciona l'autenticació de contrasenya en mode -listen
		VncPassword="$(printf '%s' "$VnciSpecification" | cut -sf 4 -d ':')"
		VnciFlags="$(printf '%s' "$VnciSpecification" | cut -sf 5 -d ':')"
		if [ "$(echo ",${DisplayChannels}," | grep -ie ",vnci,")" != "" ] && [ "$SessioEscriptori" != "" ] ; then
			# Llancem un visor només si s'ha especificat vnci sense més
			LlansemVisorVnci="1"
		fi
	fi
	VncdPort=0
#	if [ "$(echo ",${DisplayChannels}," | grep -ie ",vnc,")$(echo ",${DisplayChannels}," | grep -ie ",vnc:")" != "" ] ; then
	if [ "$(printf '%s' ",${DisplayChannels}," | grep -ie ',vnc:' -ie ',vnc,')" != "" ] ; then
		VncdSpecification="$(printf '%s' ",${DisplayChannels}," | sed -e 's|.*,vnc:|vnc:|gi' -e 's|.*,vnc,|vnc,|gi' | grep -ie '^vnc:' -ie '^vnc,' | head -n 1 | cut -f 1 -d ',')"
		VisioVncDirecte="1"
#		VncdHost="$(echo "$DisplayChannels" | sed -e 's|,|\n|g' | grep -ie '^vnc:' | head -n 1 | cut -s -f 2 -d ':')"
		VncdHost="$(printf '%s' "$VncdSpecification" | cut -sf 2 -d ':')"
		if [ "$VncdHost" = "" ] ; then
			# 0.0.0.0 = Connectable des de qualsevol origen; un altre valor indica la única IP pròpia que escolta connexions. Per admetre només del mateix equip: 127.0.0.1
			VncdHost="0.0.0.0"
		fi
#		VncdPort="$(echo "$DisplayChannels" | sed -e 's|,|\n|g' | grep -ie '^vnc:' | head -n 1 | cut -s -f 3 -d ':')"
		VncdPort="$(printf '%s' "$VncdSpecification" | cut -sf 3 -d ':')"
		if ! Is_IntegerNr $VncdPort || [ $VncdPort = "0" ] ; then
#			VncdPort="$(ValorVariableFichero "$ProfileFile" VncPort "$FreeVncPort")"
			VncdPort="$(IniVarValue "$ProfileFile" VncPort '' "$FreeVncPort" '=')"
		fi
#		VncPassword="$(echo "$DisplayChannels" | sed -e 's|,|\n|g' | grep -ie '^vnc:' | head -n 1 | cut -s -f 4- -d ':')"
		VncPassword="$(printf '%s' "$VncdSpecification" | cut -sf 4 -d ':')"
		VncdFlags="$(printf '%s' "$VncdSpecification" | cut -sf 5 -d ':')"
#		if [ "$(echo ",${DisplayChannels}," | grep -ie ",vnc,")" != "" ] && [ "$SessioEscriptori" != "" ] ; then
		if [ "$SessioEscriptori" != "" ] ; then
#			# Llancem un visor només si s'ha especificat vnc sense més ??!?!!
			# En mode CLI (matromus) es pot especificar vnc sense requerir escriptori.
			LlansemVisorVncd="1"
		fi
	fi
	if ! Is_Executable vncviewer || [ "$(WhereProgram screen)$(WhereProgram "$SSD")" = "" ] ; then
		if [ "$VisioVncDirecte" = "1" ] && [ "$SessioEscriptori" != "" ] ; then
			MissatgeSincron "$(echo "PROBLEMA: No s'ha trobat alguna de les eines vncviewer i/o screen o start-stop-daemon." ; echo "SOLUCIO: instalar els paquets screen/start-stop-daemon i xvnc4viewer, o be configurar nomes SDL.")"	#'
			Result=52 ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
		fi
	fi
	
	DisplayScale="$(GetSetRenamedParameter "$ProfileFile" "Scale" "DisplayScale" "1" "\n# DisplayScale (local ssvncviewer): can be a floating point ratio, e.g. "0.9", or a fraction, e.g. "3/4", or WxH, e.g. 1280x1024" 2>/dev/null)"
	
	GlobalNetworkSpec=''
	PreviesXarxa=''
	PosteriorsXarxa=''
	ANewMac="$(NewMac)"
	if [ "$ANewMac" != "" ] ; then NewMacSpec="/${ANewMac}" ; fi
#	NetChannel1="$(ValorVariableFichero "$ProfileFile" "NetChannel1" "")"
#	# Per NetChannel1 s'espera "user" o model/MAC/pont
#	if [ "$NetChannel1" = "" ] ; then
		ValorTmp="# Sintaxis admitidas de NetChannel*:"
		ValorTmp="$(printf '%s\n' "$ValorTmp" ; printf '%s\n' '#	"user"              para que tenga una red local NAT. La palabra "user" es literal. Es la forma más simple de dar salida a internet.')"
		Examples="$($QemuBin  -net nic,model=? 2>&1 | grep -ie 'models' | tr ':' '\n' | tail -n 1 | tr ',' ' ')"
		Examples="$(echo Trim$Examples | sed -e 's|^Trim||g')"
		ValorTmp="$(printf '%s\n' "$ValorTmp" ; printf '%s\n' "#	\"user/model\"        red NAT especificando modelo de NIC (tarjeta de red): $Examples")"
		ValorTmp="$(printf '%s\n' "$ValorTmp" ; printf '%s\n' "#	                    	${ParO}vea modelos posibles ejecutando: $QemuBin -net nic,model=?${ParC}")"
		ValorTmp="$(printf '%s\n' "$ValorTmp" ; printf '%s\n' '#	"user,..."          opcionalmente admite mas parametros como por ejemplo:')"
		ValorTmp="$(printf '%s\n' "$ValorTmp" ; printf '%s\n' '#	                    	(abriendo el puerto 8080 de la madre/host y redirigirlo a la MV como 80, escuchando solo por 127.0.0.1)')"
		ValorTmp="$(printf '%s\n' "$ValorTmp" ; printf '%s\n' '#	                    	"user,hostfwd=tcp:127.0.0.1:8080-:80"')"
		ValorTmp="$(printf '%s\n' "$ValorTmp" ; printf '%s\n' '#	"user...|smb=path"  red NAT con el servicio Samba para que Windows encuentre carpeta compartida en \\10.0.2.4\qemu\ . La palabra "smb" tambien es literal.')"
		ValorTmp="$(printf '%s\n' "$ValorTmp" ; printf '%s\n' '#	                    	"smb=/home/usuario/Documentos"')"
		ValorTmp="$(printf '%s\n' "$ValorTmp" ; printf '%s\n' '#	"none"              para establecer que NO haya interfaz de red. La palabra "none" es literal.')"
		ValorTmp="$(printf '%s\n' "$ValorTmp" ; printf '%s\n' '#	"model/mac"         para conectar una NIC virtual a la madre/host')"
		ValorTmp="$(printf '%s\n' "$ValorTmp" ; printf '%s\n' '#	"model/mac/bridge"  para conectar una NIC a la madre/host y a un puente de red en concreto')"
#		ValorTmp="$(printf '%s\n' "$ValorTmp" ; printf '%s\n' '')"
#		ValorTmp="$(printf '%s\n' "$ValorTmp" ; printf '%s\n' "#NetChannel1=\"virtio${NewMacSpec}\"")"
#		ModificarParametreConf "$ProfileFile" "Xarxa" "\"$Xarxa\"" 2>/dev/null
#		ValorTmp="rtl8139${NewMacSpec}"
#		echo "# NetChannel1=\"$ValorTmp\"" >> "$ProfileFile"
#	fi
	NetChannelNr=1
	NetChannel_Current="$(GetSetRenamedParameter "$ProfileFile" "Xarxa" "NetChannel1" "\"user/rtl8139${NewMacSpec}\"" "\n$ValorTmp" 2>/dev/null)"
	while [ "$NetChannel_Current" != "" ] ; do
		# As of Qemu 2.0.0 , MAX_NICS is hardcoded to 8 at net.h
		NetChannel_Setup "$NetChannel_Current"
		NetChannelNr=$(($NetChannelNr + 1))
#		NetChannel_Current="$(ValorVariableFichero "$ProfileFile" "NetChannel${NetChannelNr}" '')"
		NetChannel_Current="$(IniVarValue "$ProfileFile" "NetChannel${NetChannelNr}" '' "" '=')"
	done
	
	Only1MachineDueTo=''
	if [ "$SistemaVirtualitza" = "" ] ; then Only1MachineDueTo='KVM' ; fi
	if [ "$HostVirtualitza" = "" ] ; then
		if [ "$Only1MachineDueTo" != "" ] ; then Only1MachineDueTo="${Only1MachineDueTo}, " ; fi
		Only1MachineDueTo="${Only1MachineDueTo}BIOS"
	fi
	SingleRunPerProfile_Default=1
	if [ "$(echo "$NetChannel1" | grep -e '/' | grep -ve '^user,' -ve '^user/')" != "" ] && [ "$NicMac" != "" ] ; then
		# Si s'estableix NIC amb MAC, no poden conviure 2 instancies amb la mateixa MAC
		SingleRunPerProfile_Default=1
	else
		if [ "$MediaPersistence" = "0" ] ; then
			SingleRunPerProfile_Default=auto
		else
			# Amb persistència, només si es tracta de suports ROM
			if [ "$BootMedia" = "" ] || Is_RomMedia "$BootMedia" || Is_OpticalMedia "$BootMedia" ; then
				if [ "$Media2" = "" ] || Is_RomMedia "$Media2" || Is_OpticalMedia "$Media2" ; then
					SingleRunPerProfile_Default=auto
				else
					SingleRunPerProfile_Default=1
				fi
			else
				SingleRunPerProfile_Default=1
			fi
		fi
	fi
	ValorTmp="# SingleRunPerProfile: Si hay que evitar varias instancias del mismo perfil de MV;"
	ValorTmp="$(echo "$ValorTmp" ; echo '#	1	para evitar una segunda ejecucion de MV por el mismo perfil')"
	ValorTmp="$(echo "$ValorTmp" ; echo '#	0	para permitir multiples ejecuciones de MV por el mismo perfil')"
	ValorTmp="$(echo "$ValorTmp" ; echo '#	auto	permitir solo si no se preve conflicto entre discos/ficheros o redes con MAC')"
	SingleRunPerProfile="$(GetOrSetIniVarValue "$ProfileFile" SingleRunPerProfile '' "$SingleRunPerProfile_Default" '=' '' "\n$ValorTmp" "$ReadOnly" 2>/dev/null)"
	if [ "$SingleRunPerProfile" = "auto" ] ; then
		SingleRunPerProfile="$SingleRunPerProfile_Default"
	fi
	if [ "$SingleRunPerProfile" = "auto" ] ; then
		# En último caso, no se ha encontrado nada que interfiera, PERO FALTA VER SI OTRA INSTANCIA USA MEDIA1 O MEDIA2 EN R/W !
		SingleRunPerProfile=0
	fi
	
#	PreviousCommand="$(ParametroEstablecidoConf "$ProfileFile" "PreviousCommand" "\"\"" "# PreviousCommand: Accion a ejecutar antes de lanzar la maquina virtual." 2>/dev/null)"
#	PreviousCommand="$(GetOrSetIniVarValue "$ProfileFile" PreviousCommand '' "\"\"" '=' '' "\n# PreviousCommand: Accion a ejecutar antes de lanzar la maquina virtual." "$ReadOnly" 2>/dev/null)"
	PreviousCommand="$(GetOrSetIniVarValue "$ProfileFile" PreviousCommand '' "" = '' "\n# PreviousCommand: Accion a ejecutar antes de lanzar la maquina virtual." "$ReadOnly" 2>/dev/null)"
	
	ValorTmp="# PreviousErrorAbortsMessage: En caso que PreviousCommand de error, no se lanza la MV y se muestra el texto;"
	ValorTmp="$(echo "$ValorTmp" ; echo "# Sin texto, se lanza la MV incondicionalmente.")"
#	PreviousErrorAbortsMessage="$(ParametroEstablecidoConf "$ProfileFile" "PreviousErrorAbortsMessage" "\"\"" "$ValorTmp" 2>/dev/null)"
	PreviousErrorAbortsMessage="$(GetOrSetIniVarValue "$ProfileFile" PreviousErrorAbortsMessage '' "\"\"" '=' '' "\n$ValorTmp" "$ReadOnly" 2>/dev/null)"
	
#	PosteriorCommand="$(ParametroEstablecidoConf "$ProfileFile" "PosteriorCommand" "\"\"" "# PosteriorCommand: Accion a ejecutar al finalizar la maquina virtual." 2>/dev/null)"
	PosteriorCommand="$(GetOrSetIniVarValue "$ProfileFile" PosteriorCommand '' "\"\"" '=' '' "\n# PosteriorCommand: Accion a ejecutar al finalizar la maquina virtual." "$ReadOnly" 2>/dev/null)"
	
	# KeepProfileLogs el mantenim només com a característica oculta; no l'escrivim als nous perfils .matromu
	#ValorTmp="$(GetSetRenamedParameter "$ProfileFile" "ConservarBitacora" "KeepProfileLogs" "0" "\n# KeepProfileLogs: Si se conserva la BitacoraPerfil .log cuando no hay problemas (1)." 2>/dev/null)"
#	ValorTmp="$(ValorVariableFichero "$ProfileFile" "KeepProfileLogs" "")"
	ValorTmp="$(IniVarValue "$ProfileFile" KeepProfileLogs '' "" '=')"
#	if [ "$ValorTmp" = "" ] ; then ValorTmp="$(ValorVariableFichero "$ProfileFile" "ConservarBitacora" "0")" ; fi
	if [ "$ValorTmp" = "" ] ; then ValorTmp="$(IniVarValue "$ProfileFile" ConservarBitacora '' "0" '=')" ; fi
	if [ "$KeepProfileLogs" != "1" ] ; then KeepProfileLogs="$ValorTmp" ; fi
	
	ValorTmp="# SuperuserOnly: Si para el usuario normal se invocara sudo/gksudo para la ejecucion (1);"
	ValorTmp="$(echo "$ValorTmp" ; echo "# Normalmente necesario para iniciar desde un dispositivo real o establecer NIC diferente de \"user\".")"
	SuperuserOnly="$(GetSetRenamedParameter "$ProfileFile" "RequerirRoot" "SuperuserOnly" "0" "\n$ValorTmp" 2>/dev/null)"
	if [ "$SuperuserOnly" = "1" ] && [ $(id -u) -ne 0 ] ; then
		AmbPrefixSudo="$(PrefixSudo) "
	fi
	
	Respawn="$(GetSetRenamedParameter "$ProfileFile" "AutoRestart" "Respawn" "0" "\n# Respawn: 0 to end when machine stops; 1 to start again when machine stops." 2>/dev/null)"
	
	Examples="$(WhereProgram $QemuBin)"
	if [ "$Examples" != "" ] ; then
		QemusDir="$(dirname "$Examples")"
		QemusPrefix='qemu-system-'
		Examples="$(ls -1 "$QemusDir" | grep -e "^${QemusPrefix}" | cut -f 3- -d '-')"
		if [ "$Examples" = "" ] ; then
			QemusPrefix='qemu-'
			Examples="$(ls -1 "$QemusDir" | grep -e "^${QemusPrefix}" | cut -f 3- -d '-')"
		fi
		Examples="$(echo $(echo $Examples | tr -s ' ' '\n' | sort))"
		ValorTmp="# Architecture (opcional): $Examples"
		ValorTmp="$(echo "$ValorTmp" ; echo "# Vea variantes ejecutando: ls -1 ${QemusDir}/${QemusPrefix}*")"
	fi
	if [ "$Examples" = "" ] ; then
		Examples="i386 x86_64 arm ppc etc."
		ValorTmp="# Architecture (opcional): $Examples"
	fi
	ProfileArchitecture="$(GetSetRenamedParameter "$ProfileFile" "TipusPlataforma" "Architecture" "\"\"" "\n$ValorTmp" 2>/dev/null)"
	Examples="$("$QemuBin" -M ? | grep -ve ':$' | cut -f 1 -d ' ')"
	Examples="$(echo $(echo $Examples | tr -s ' ' '\n' | sort))"
	if [ "$Examples" = "" ] ; then
		Examples="pc-i440fx-2.0 n800 mac99 etc."
	fi
	ValorTmp="# Chipset (opcional): ${Examples};"
	ValorTmp="$(echo "$ValorTmp" ; echo "# Vea posibilidades ejecutando: $QemuBin -M ?")"
	ProfileChipset="$(GetSetRenamedParameter "$ProfileFile" "GamaMaquina" "Chipset" "\"\"" "\n$ValorTmp" 2>/dev/null)"
	Examples="$("$QemuBin" -cpu ? | grep -ve '^ ' | grep -ve ':$' | tr -s ' ' | cut -f 2 -d ' ')"
	Examples="$(echo $(echo $Examples | tr -s ' ' '\n' | sort))"
	if [ "$Examples" = "" ] ; then
		Examples="pentium2 G3 etc."
	fi
	ValorTmp="# CPU (opcional): ${Examples};"
	ValorTmp="$(echo "$ValorTmp" ; echo "# Vea posibilidades ejecutando: $QemuBin -cpu ?")"
	ProfileCPU="$(GetSetRenamedParameter "$ProfileFile" "Processador" "ProfileCPU" "\"\"" "\n$ValorTmp" 2>/dev/null)"
	if [ "$QemuBin" != "" ] ; then
		QemuVersion="$("$QemuBin" -version | sed -e 's/ /\n/g' | grep -e '^[0123456789]' | head --lines=1)"
	else
		MissatgeSincron "$(echo "PROBLEMA: No s'ha trobat el programa Qemu" ; echo "SOLUCIO: instalar el programari de virtualitzacio")"	#'
		Result=57 ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
	fi
	
	ValorTmp='# ExtraParameters: texto a agregar a la llamada de Qemu. Ejemplos para:'
	if [ "$(ComparaVersions $QemuVersion 4.0.0)" = "<" ] ; then
		ValorTmp="$(echo "$ValorTmp" ; echo "#	adaptador de sonido:                 -soundhw es1370 ${ParO}vea posibilidades ejecutando: $QemuBin -audio model=help${ParC}")"
	else
		if [ "$(ComparaVersions $QemuVersion 7.1.0)" = "<" ] ; then
			ValorTmp="$(echo "$ValorTmp" ; echo "#	adaptador de sonido:                 -device ES1370 ${ParO}vea posibilidades ejecutando: $QemuBin -audio model=help${ParC}")"
		else
			# audio-pa requires "qemu-system-gui" package.
#			ValorTmp="$(echo "$ValorTmp" ; echo "#	adaptador de sonido:                 -audio pa,model=hda ${ParO}vea posibilidades ejecutando: $QemuBin -audio model=help${ParC}")"
			ValorTmp="$(echo "$ValorTmp" ; echo "#	adaptador de sonido:                 -audio alsa,model=hda ${ParO}vea posibilidades ejecutando: $QemuBin -audio model=help${ParC}")"
		fi
	fi
	if [ "$(ComparaVersions $QemuVersion 2.8.0)" = ">" ] ; then
		ValorTmp="$(echo "$ValorTmp" ; echo '#	conectar dispositivo USB real:       -device usb-host,hostbus=2,hostaddr=3')"
#		ValorTmp="$(echo "$ValorTmp" ; echo '#	conectar dispositivo USB real:       -device usb-host,046d:08b2')"
	else
		ValorTmp="$(echo "$ValorTmp" ; echo '#	conectar dispositivo USB real:       -usbdevice host:046d:08b2')"
	fi
#	ValorTmp="$(echo "$ValorTmp" ; echo '#	no mostrar marcos de ventana SDL:    -no-frame')"
#	ValorTmp="$(echo "$ValorTmp" ; echo '#	conectar disco duro real:            -drive file=/dev/hdb,media=disk,index=2,cache=writeback')"
#	ValorTmp="$(echo "$ValorTmp" ; echo '#	conectar unidad de CD/DVD real:      -drive file=/dev/cdrom,media=cdrom,index=3')"
	ValorTmp="$(echo "$ValorTmp" ; echo '#	delegar toda escritura a cache:      cache=unsafe')"
	ValorTmp="$(echo "$ValorTmp" ; echo '#	conectar puerto S232 real:           -serial /dev/ttyS0')"
	ValorTmp="$(echo "$ValorTmp" ; echo '#	establecer tiempo del reloj:         -rtc base=2006-06-17T16:01:21,clock=vm')"
	if [ "$(ComparaVersions $QemuVersion 5.2.0)" = "<" ] ; then
		ValorTmp="$(echo "$ValorTmp" ; echo '#	activar/desactivar expresamente VT:   -enable-kvm -no-kvm')"
	else
		ValorTmp="$(echo "$ValorTmp" ; echo '#	desactivar VT:                       -machine accel=tcg')"
	fi
	ValorTmp="$(echo "$ValorTmp" ; echo '#	grafica compatible Cirrus CLGD 5446: -vga cirrus')"
	ValorTmp="$(echo "$ValorTmp" ; echo '#	grafica acelerada VESA 2 VBE:        -vga std')"
	ValorTmp="$(echo "$ValorTmp" ; echo '#	grafica sin limites:                 -vga virtio')"
	ValorTmp="$(echo "$ValorTmp" ; echo '#	V.RAM distinta a los 16MiB predet.:  -global VGA.vgamem_mb=64')"
	if [ "$(ComparaVersions $QemuVersion 3.1.0)" = "<" ] ; then
		ValorTmp="$(echo "$ValorTmp" ; echo '#	Hora local para Windows:             -localtime')"
	else
		ValorTmp="$(echo "$ValorTmp" ; echo '#	Hora local para Windows:             -rtc base=localtime')"
	fi
	ValorTmp="$(echo "$ValorTmp" ; echo '#	pantalla completa (sin ventana):     -full-screen')"
	ValorTmp="$(echo "$ValorTmp" ; echo '#	No crear dispositivos habituales:    -nodefaults')"
	ValorTmp="$(echo "$ValorTmp" ; echo '#	1 CPUs x 2 nucleos x2 hilos (dan 4 procesos en host):    -smp sockets=1,cores=2,threads=2')"
	ValorTmp="$(echo "$ValorTmp" ; echo '#	1 CPUs x 1 nucleos x4 hilos (dan 4 procesos en host):    -smp sockets=1,cores=1,threads=4')"
	ValorTmp="$(echo "$ValorTmp" ; echo '#	8 CPUs x 6 nucleos x4 hilos (dan 192 procesos en host):  -smp sockets=8,cores=6,threads=4')"
	ValorTmp="$(echo "$ValorTmp" ; echo '#	Dirigir p. 8080 de madre a cria 80 en modo user/NAT: -redir tcp:8080::80')"
#	ValorTmp="$(ParametroEstablecidoConf "$ProfileFile" "ExtraParameters" "\"\"" "$ValorTmp" 2>/dev/null)"	# ExtraParameters already read (and revised) before.
	ValorTmp="$(GetOrSetIniVarValue "$ProfileFile" ExtraParameters '' "\"\"" '=' '' "\n$ValorTmp" "$ReadOnly" 2>/dev/null)"	# ExtraParameters already read (and revised) before.
	
	if [ "$(StringWithParameters "$ExtraParameters" '-enable-kvm' '-no-kvm')" = "" ] ; then
		if [ "$SistemaVirtualitza" != "" ] ; then
			ModeKVM=" -enable-kvm"
		else
			if [ "$("$QemuBin" -accel help | grep -e '^kvm$')" = "" ] ; then
				# Versions that present accelerators in this "one per line" format, deprecated "-no-kvm"
				ModeKVM=" -no-kvm"
			else
				ModeKVM=""
			fi
		fi
	else
		ModeKVM=""
	fi
	if [ $ResultN -eq 0 ] ; then
		ParametresPlataforma="$(GetPlatformParameters "$QemuBin" "$ProfileChipset" "$ProfileCPU" "$ExtraParameters")"
		#if [ "$ParametresPlataforma" = "" ] ; then ParametresPlataforma="-M pc -cpu host" ; fi
	fi

	return $ResultN
}

LlansarVnci ()
{
	local VVParameters=""
	local RelativePort=''
	
	VncJaEstava="0"
	PortsJaEscoltats=="$(ps -A -o pid,cmd | grep -ive "[[:blank:]]grep[[:blank:]]" | grep -ie "vncv" | grep -E "[[:blank:]]-listen[[:blank:]]")"
	PortsJaEscoltats="$(NextWordTo "$PortsJaEscoltats" "-listen" 1)"
	if [ "$(echo " $PortsJaEscoltats " | grep -e " $VnciPort ")" = "" ] ; then
#		RelativePort=$((VnciPort + 5900))
		RelativePort=$VnciPort
		VVParameters=" -FullColor SendClipboard AcceptClipboard -listen $RelativePort"
		if [ "$(StringWithParameters "$ExtraParameters" "-full-screen")" = "" ] ; then
			VVParameters=" -FullScreen -MenuKey Super_L${VVParameters}"
		fi
		echo "screen -d -m vncviewer${VVParameters}"
		screen -d -m vncviewer${VVParameters}
	else
		VncJaEstava="1"
	fi
}

LlansarVncDirecte ()
{
	local ResultFinalitzat="$1"
	local RelativePort=0
	local VVParameters=""
	local DetectedListeners=''
	local CurListener=''
	local CurListenerPort=''
	local CurListenerHasViewer=0
	local DetectedViewers=''
	local CurViewer=''
	local CurViewerPort=''
	local RemainS=30
	local Result=0
	local ResultN=0
	
#	if [ "$(Which netstat)" = "" ] || [ "$ExecucioDescartada" = "1" ] ; then
#		sleep 1
		DetectedListeners="$(ps -A -o comm,cmd | grep -e "^qemu.*file=${BootMedia}," | grep -e ' -vnc ' | grep -ve 'grep')"
		while [ "$DetectedListeners" = "" ] && [ ! -f "$ResultFinalitzat" ] && [ $RemainS -gt 0 ] ; do
			printf '%s\n' "Waiting Qemu to be running, before connecting to its VNC service..."
			sleep 1
			DetectedListeners="$(ps -A -o comm,cmd | grep -e "^qemu.*file=${BootMedia}," | grep -e ' -vnc ' | grep -ve 'grep')"
			RemainS=$(($RemainS - 1))
		done
#	else
#		while [ "$(env LANG=en netstat -nlp 2>/dev/null | grep -E "[[:blank:]]LISTEN[[:blank:]]" | grep -E '^tcp[[:blank:]]' | grep -E ":${VncdPort}[[:blank:]]")" = "" ] && [ ! -f "$ResultFinalitzat" ] ; do
#			printf '%s\n' "Waiting port TCP $VncdPort to be listening, and connect to it..."
#			sleep 1
#		done
#	fi
	
	if [ "$DetectedListeners" != "" ] ; then
		VncdPort=""
		DetectedViewers="$(ps -A -o cmd | grep -e "vncviewer ")"
		IFS="$(printf '\n\b')" ; for CurListener in $DetectedListeners ; do unset IFS
			CurListenerHasViewer=0
			CurListenerPort="$(printf '%s\n' "$CurListener" | tr -s '-' '\n' | grep -e '^vnc .*:.' | cut -f 2 -d ' ' | cut -f 2 -d ':' | cut -f 1 -d ',')"
			if ! Is_IntegerNr "$CurListenerPort" ; then
				CurListenerPort=5900
			else
				# Relative to absolute
				CurListenerPort=$(($CurListenerPort + 5900))
			fi
			if [ $CurListenerPort -lt 100 ] ; then CurListenerPort=$(($CurListenerPort + 5900)) ; fi
			IFS="$(printf '\n\b')" ; for CurViewer in $DetectedViewers ; do unset IFS
				CurViewerPort="$(printf '%s\n' "$CurViewer" | grep -e ':' | cut -f 2 -d ':' | cut -f 1 -d ' ')"
				if ! Is_IntegerNr "$CurViewerPort" ; then CurViewerPort=5900 ; fi
				if [ $CurViewerPort -lt 100 ] ; then CurViewerPort=$(($CurViewerPort + 5900)) ; fi
				if [ $CurViewerPort -eq $CurListenerPort ] ; then
					CurListenerHasViewer=1
				fi
			done
			if [ $CurListenerHasViewer -ne 1 ] ; then VncdPort=$CurListenerPort ; fi
		done
		if [ "$VncdPort" = "" ] ; then VncdPort=$CurListenerPort ; fi	# Force last found
		RemainS=4
		# Wait a bit for VNC port being listened
		while [ $RemainS -gt 0 ] && [ "$(env LANG=en netstat -tln | grep -ie "^tcp.*:${VncdPort} .* LISTEN")" = "" ] ; do
			sleep 1
			RemainS=$(($RemainS - 1))
		done
		if [ $VncdPort -ge 5900 ] && [ $VncdPort -lt 6000 ] ; then
			RelativePort=$(($VncdPort - 5900))
		else
			RelativePort=$VncdPort
		fi
		if [ "$DisplayScale" != "" ] && [ "$DisplayScale" != "1" ] && ! Is_Executable ssvncviewer ; then
			MissatgeAssincron "AVIS: Es demana DisplayScale pero falta instalar ssvnc"
		fi
		if [ "$DisplayScale" != "" ] && [ "$DisplayScale" != "1" ] && Is_Executable ssvncviewer ; then
			VVParameters=" -x11cursor -noshared -truecolor -scale $DisplayScale localhost:${RelativePort}"
			if [ "$(StringWithParameters "$ExtraParameters" "-full-screen")" != "" ] ; then
				VVParameters=" -fullscreen${VVParameters}"
			fi
			echo '$' "ssvncviewer${VVParameters}" | tee -a "$BitacoraPerfil"
			ssvncviewer${VVParameters} 2>&1
			Result=$? ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
		else
			if [ "$(ReadlinkF $(WhereProgram vncviewer) | grep -e 'tigervnc')" != "" ] ; then
				# xtigervncviewer seems to not translate VNC port number
				VVParameters=" -FullColor localhost:${VncdPort}"
			else
				if [ "$(ReadlinkF $(WhereProgram vncviewer) | grep -e 'tightvnc')" != "" ] ; then
					# xtigervncviewer seems to not translate VNC port number
					VVParameters=" -truecolour localhost:${RelativePort}"
				else
					VVParameters=" -FullColor localhost:${RelativePort}"
				fi
			fi
			if [ "$(StringWithParameters "$ExtraParameters" "-full-screen")" != "" ] ; then
				VVParameters=" -FullScreen -MenuKey Super_L${VVParameters}"
			fi
			echo '$' "vncviewer${VVParameters}" | tee -a "$BitacoraPerfil"
			vncviewer${VVParameters}
			Result=$? ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
		fi
	else
		Result=109 ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
	fi
	return $ResultN
}

GetParametresVncQemu ()
# Descripcio:	Retorna els paràmetres addicionals per a què Qemu serveixi la visualització per a
#		VNC directe.
# Correcció de desplaçament del punter:
#	Amb el pedaç "-usbdevice tablet" MS/Windows XP o superior s'autoconfigura una tauleta assenyaladora
#	i coincideix amb el punter de VNC. MS/Windows 98 o inferior sembla necessitar controladors.
{
	local RelativePort=0
	local PasswordParameter=""
	local TabletParameter=''
	local RelativePort=''
	local Value=''
	
	if [ "$(ComparaVersions $QemuVersion 2.8.1)" = ">" ] ; then
		TabletParameter=' -usb -device usb-tablet'
	else
		TabletParameter=' -usb -usbdevice tablet'
	fi
	if [ $VncdPort -ge 5900 ] ; then
		RelativePort=$(($VncdPort - 5900))
	else
		RelativePort="-$((5900 - $VncdPort))"
	fi
	if [ "$VncPassword" != "" ] ; then
		# No es pot diferenciar el password entre vnc i vnci perquè la instrucció de Qemu "change vnc password" és única.
		if [ "$(ComparaVersions $QemuVersion 6.0.0)" = "<" ] ; then
			PasswordParameter=",password"
		else
			PasswordParameter=",password=on"
		fi
	fi
	if [ "$VisioVncInvers" = "1" ] ; then
#		QemuVnciPort=$VnciPort
#		if [ $QemuVnciPort -ge 5900 ] ; then
#			QemuVnciPort=$(($QemuVnciPort - 5900))
#		else
#			# https://bugzilla.redhat.com/show_bug.cgi?id=1352620
#			printf '%s\n' "W: VNC port number for reverse connection should be higher than 5900, due to display number conversion Qemu does ${ParO}-5900${ParC}." 1>&2
#			printf '%s\n' "   Sadly it can not be the 5500 standard due to negative conversion Matromu parses." 1>&2
#		fi
#		RelativePort=$((VnciPort + 5900))
		RelativePort=$VnciPort
		if [ "$DisplayChannels" = "curses" ] && [ "$(ComparaVersions $QemuVersion 4.0.0)" != "<" ] ; then
			# https://bugs.debian.org/583478
			Value="$Value -vnc ${VnciHost}:${RelativePort},reverse${PasswordParameter}${TabletParameter}"
		else
			Value="$Value -vnc ${VnciHost}:${RelativePort},reverse${PasswordParameter} -k es${TabletParameter}"
		fi
	fi
	PasswordParameter=""
	if [ "$VisioVncDirecte" = "1" ] ; then
		if [ "$VncPassword" != "" ] ; then
			if [ "$(ComparaVersions $QemuVersion 6.0.0)" = "<" ] ; then
				PasswordParameter=",password"
			else
				PasswordParameter=",password=on"
			fi
		fi
		if [ "$DisplayChannels" = "curses" ] && [ "$(ComparaVersions $QemuVersion 4.0.0)" != "<" ] ; then
			# https://bugs.debian.org/583478
			Value="$Value -vnc ${VncdHost}:${RelativePort}${PasswordParameter}${TabletParameter}"
		else
			Value="$Value -vnc ${VncdHost}:${RelativePort}${PasswordParameter} -k es${TabletParameter}"
		fi
	fi
	if [ "$Value" != "" ] ; then echo "$Value" ; fi
}

MatarVNC ()
{
	local RelativePort=''
	if [ "$VisioVncInvers" = "1" ] ; then
#		RelativePort=$((VnciPort + 5900))
		RelativePort=$VnciPort
		ProcesVnc="$(ps -A -o pid,comm,args | grep -ivE '([[:blank:]]grep[[:blank:]]|^grep[[:blank:]])' | grep -iE '(vncv|vnc4v)' | grep -E "[[:blank:]]-listen $RelativePort")"
		ProcesVnc="$(UnaParaula () { echo $1; }; UnaParaula $ProcesVnc)"
	else
		RelativePort=$VncdPort
		ProcesVnc="$(ps -A -o pid,comm,args | grep -ivE '([[:blank:]]grep[[:blank:]]|^grep[[:blank:]])' | grep -iE '(vncv|vnc4v)' | grep -E "[[:blank:]]localhost:$RelativePort")"
		ProcesVnc="$(UnaParaula () { echo $1; }; UnaParaula $ProcesVnc)"
	fi
	if [ "$ProcesVnc" != "" ] ; then
		kill $ProcesVnc
		sleep 1
		kill -9 $ProcesVnc 2>/dev/null
	fi
}

RunDirCreat ()
# Crea /tmp/matromu/$ProfileID/$RunID amb l'escala de permisos adequats.
{
	local ProfileID="$1"
	local RunID="$2"
	local Result=0
	local ResultN=0
	
	if [ ! -d "$DirTemp" ] ; then DirTemp="/run/shm" ; fi
	if [ ! -d "$DirTemp" ] ; then DirTemp="/tmp" ; fi
	if [ ! -d "${DirTemp}/matromu" ] ; then
		rm -f "${DirTemp}/matromu"
		mkdir -p "${DirTemp}/matromu"
		Result=$? ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
		# Per a què altres usuaris puguin utilitzar.
		chmod a+rwX "${DirTemp}/matromu"
		Result=$? ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
	fi
	if [ ! -d "${DirTemp}/matromu/${ProfileID}" ] ; then
		mkdir -p "${DirTemp}/matromu/${ProfileID}"
		Result=$? ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
		# Per a què altres usuaris puguin utilitzar el mateix perfil per altres execucions.
		chmod a+rwX "${DirTemp}/matromu/${ProfileID}"
		Result=$? ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
	fi
	if [ ! -d "${DirTemp}/matromu/${ProfileID}/${RunID}" ] ; then
		mkdir -p "${DirTemp}/matromu/${ProfileID}/${RunID}"
		Result=$? ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
		# Per a un us privat.
		chmod u=rwX,g=rX,o= "${DirTemp}/matromu/${ProfileID}/${RunID}"
		Result=$? ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
	fi
	if [ -d "${DirTemp}/matromu/${ProfileID}/${RunID}" ] ; then
		echo "${DirTemp}/matromu/${ProfileID}/${RunID}"
	fi
	return $ResultN
}

FitxerTestimoniCreat ()
{
	local ProfileID="$1"
	local RunID="$2"
	local Valor=""
	local Result=0
	local ResultN=0
	
	Valor="$(RunDirCreat "$ProfileID" "$RunID")/matromu.conf"
	Result=$? ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
	if [ $ResultN -eq 0 ] ; then
		echo "# $(date +'%F %T %N')" > "$Valor"
		echo "DisplayChannels=\"$DisplayChannels\"" >> "$Valor"
		echo "RutaTreball=\"$(pwd)\"" >> "$Valor"
		echo "BootMedia=\"$BootMedia\"" >> "$Valor"
		if [ "$(StringWithParameters "$ExtraParameters" "-m")" = "" ] ; then
			echo "MemoryQuotaMiB=$MemoryQuotaMiB" >> "$Valor"
		fi
		echo "VnciPort=$VnciPort" >> "$Valor"
		echo "MediaPersistence=$MediaPersistence" >> "$Valor"
		echo "NetChannel1=\"$NetChannel1\"" >> "$Valor"
		echo "ProfileID=\"$ProfileID\"" >> "$Valor"
		echo "RunID=\"$RunID\"" >> "$Valor"
		echo "$Valor"
	fi
	return $ResultN
}


##### MAIN SCRIPT #####

Result=0
ResultN=0
ParO='(' ; ParC=')' ; Tab="$(printf '\t')"

if [ ! -d "$DirTemp" ] ; then DirTemp="/run/shm" ; fi
if [ ! -d "$DirTemp" ] ; then DirTemp="/tmp" ; fi
if [ ! -d "$DirTempX" ] ; then DirTempX="/tmp" ; fi
PreviousDir="$(pwd)"
MeCallFile="$0"
MeDir="$(Dirname "$MeCallFile")"
cd "$MeDir"
MeDir="$(pwd)"
cd "$PreviousDir"
MeCallFile="${MeDir}/$(printf '%s\n' "$MeCallFile" | tr -s '/' '\n' | tail -n 1)"
MeExecutable="$(ReadlinkF "$MeCallFile")"

if [ "$1" = "--wait-wan-nic" ] ; then
	StopFile="$2"
	while [ "$(DefaultNICs)" = "" ] && [ ! -f "$StopFile" ] ; do
		sleep 1
	done
	sleep 1
	while [ "$(DefaultNICs)" = "" ] && [ ! -f "$StopFile" ] ; do
		sleep 1
	done
	exit 0
fi

if [ "$1" = "install" ] ; then
	if [ $(id -u) -eq 0 ] ; then
		cp "$MeExecutable" "$ProgramExecutablePath"
		Result=$? ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
		chown root:root "$ProgramExecutablePath"
		Result=$? ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
		chmod u=rwx,go=rx "$ProgramExecutablePath"
		Result=$? ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
		if [ $ResultN -eq 0 ] ; then
			printf '%s\n' "Lanzador de maquina virtual con Qemu instalado como $ProgramExecutablePath"
		fi
		exit $ResultN
	else
		printf '%s\n' "${sERROR}E: Install actions need to be run with superuser ${ParO}root${ParC} permissions.${fRESET}" 1>&2
		Result=45 ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
	fi
fi

if [ "$(echo "$BootMedia" | grep -ie '^file://')" != "" ] ; then
	BootMedia="$(echo "$BootMedia" | cut -c 8-)"
fi
DirectorioPrevio="$(pwd)"
if [ ! -b "$BootMedia" ] ; then
	cd "$(dirname "$BootMedia")"
fi
LlansemVisorVncd="0"
LlansemVisorVnci="0"
VisioVncDirecte="0"
VisioVncInvers="0"
ExecucioDescartada="0"
BitacoraPerfil=""
ModeKVM=""
LimiteMemoriaQemu=2047
BitsSistema="$(file $(WhereProgram file) | tr -s "," "\n" | head --lines=1 | cut -f 2 -d ":" | cut -f 1 -d "-")"
BitsSistema="$(UnaParaula () { echo $2; }; UnaParaula $BitsSistema)"
if [ "$BitsSistema" = "64" ] ; then
	LimiteMemoriaQemu=0
	if [ "$(ComparaVersions $QemuVersion 4.0.0)" != "<" ] ; then
#		LimiteMemoriaQemu=$((7 * 512))
		LimiteMemoriaQemu=$((63 * 1024))
		if [ "$(ComparaVersions $QemuVersion 1.0.0)" != "<" ] ; then
			# Versión inventada; Debian 7 con Qemu 1.1.2 demuestra emular más de 14GiB de RAM, y combinando swap del host demuestra emular 700GiB de RAM
			# Ubuntu 14.04 no arranca con más de 65024 MiB de RAM, y Debian 7 con algo más de 65000 MiB. Fedora 20 tampoco llega a 65100 MiB.
			LimiteMemoriaQemu=0
		fi
	fi
fi

if [ $ResultN -eq 0 ] ; then
	if [ "$BootMedia" = "" ] ; then
		MissatgeSincron "PROBLEMA: Cal especificar un fitxer-imatge de disc o perfil .matromu per iniciar un sistema virtualitzat."
		Result=81 ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
		KeepProfileLogs="1"
	fi
fi
if [ $ResultN -eq 0 ] ; then
	Configuracio
	Result=$? ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
fi
if [ $ResultN -eq 0 ] ; then
	if [ ! -f "$BootMedia" ] && [ ! -b "$BootMedia" ] ; then
		if [ "$(StringWithParameters "$ExtraParameters" "-drive")" = "" ] ; then
			MissatgeSincron "PROBLEMA: Fitxer o dispositiu no trobat: $BootMedia"
			Result=95 ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
			KeepProfileLogs="1"
		fi
	fi
fi
#if [ $ResultN -eq 0 ] ; then
#	if [ "$SingleRunPerProfile" = "1" ] && [ "$(ps -A -o comm | grep -iE "^(qemu$|qemu-|kvm)")" != "" ] ; then
#		MissatgeSincron "$(echo "Ja tens aquesta maquina virtual funcionant." ; echo "Nomes pot treballar una maquina alhora del mateix perfil.")"
#		Result=1 ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
#		KeepProfileLogs="1"
#	fi
#fi
if [ $ResultN -eq 0 ] ; then
	if [ "$SingleRunPerProfile" = "1" ] || [ "$Only1MachineDueTo" != "" ] ; then
		FitxerLock="${DirectoriBase}/${ProfileID}.lock"
		if [ ! -f "$FitxerLock" ] ; then
			FitxerLock="$(find "${DirectoriBase}/${ProfileID}.lock" -maxdepth 0 -type l 2>/dev/null)"
		fi
		if [ -f "$FitxerLock" ] ; then
			# -a és cert només si l'enllaç funciona.
			if [ "$(ps -A -o cmd | grep -ie "^$QemuBin " | grep -e "$BootMedia")" != "" ] ; then
				# Sempre i quan hi hagi algun procés «qemu» rodant amb la mateixa imatge de disc.
				if [ "$LlansemVisorVncd" = "1" ] ; then
					MissatgeSincron "$(echo "VNCd" ; echo "Ja tens aquesta maquina virtual engegada." ; echo "S'intentara tornar a connectar la imatge.")"	#'
					ExecucioDescartada="1"
#					if [ "$SessioEscriptori" != "" ] ; then
						# En mode CLI (matromus) es pot especificar vnc sense requerir escriptori.
						LlansarVncDirecte "${DirTemp}/matromu/${ProfileID}/${RunID}/result.num"
						Result=$? ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
#						Result=1 ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
						# En aquest punt, si després d'un segon el procés concret de Qemu encara
						# està corrent, caldria oferir reconnectar-hi.
#					fi
				else
					if [ "$VisioSDL" = "1" ] ; then
						if [ $MediaPersistence -ne 0 ] ; then
							ExecucioDescartada="1"
							MissatgeSincron "$(echo "SDL" ; echo "Ja tens aquesta maquina virtual funcionant." ; echo "Nomes pot treballar una maquina alhora del mateix perfil.")"
							Result=113 ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
							KeepProfileLogs="1"
						fi
					else
						ExecucioDescartada="1"
						MissatgeSincron "$(echo "Ja tens aquesta maquina virtual engegada (no l'havies aturat)." ; echo "Si no veus la imatge, cal reiniciar l'ordinador.")"
						Result=113 ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
						KeepProfileLogs="1"
					fi
				fi
			else
				# Fitxer .lock residual?
				rm "$FitxerLock"
				if [ "$LlansemVisorVnc" = "1" ] ; then
					MissatgeSincron "$(echo "VNCd" ; echo "Ja tens una maquina virtual funcionant." ; echo "Aquest equip nomes en pot fer treballar una alhora." ; echo "S'intentara connectar la imatge si es la mateixa.")"	#'
					ExecucioDescartada="1"
					if [ "$SessioEscriptori" != "" ] ; then
						# En mode servidor (matromus) es pot especificar vnc sense requerir escriptori.
						LlansarVncDirecte "${DirTemp}/matromu/${ProfileID}/${RunID}/result.num"
						Result=$? ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
#						Result=1 ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
						# En aquest punt, si després d'un segon el procés concret de Qemu encara
						# està corrent, caldria oferir reconnectar-hi.
					fi
				else
					if [ "$Only1MachineDueTo" != "" ] && [ "$(ps -A -o comm | grep -iE "^(qemu$|qemu-|kvm)")" != "" ] ; then
						ExecucioDescartada="1"
						MissatgeSincron "$(echo "Ja tens una maquina virtual funcionant." ; echo "Aquest equip nomes en pot fer treballar una alhora" ; echo "degut a la falta de suport de: $Only1MachineDueTo")"
						Result=113 ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
						KeepProfileLogs="1"
					fi
				fi
			fi
		else
			if [ "$Only1MachineDueTo" != "" ] && [ "$(ps -A -o comm | grep -iE "^(qemu$|qemu-|kvm)")" != "" ] ; then
				MissatgeSincron "$(echo "Ja tens una altra maquina virtual funcionant." ; echo "Aquest equip nomes en pot fer treballar una alhora." ; echo "degut a la falta de suport de: $Only1MachineDueTo")"
				Result=113 ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
				KeepProfileLogs="1"
			fi
		fi
	fi
fi
if [ $ResultN -eq 0 ] && [ "$ExecucioDescartada" != "1" ] ; then
	if [ "$PreviousCommand" != "" ] ; then
		InformarEsdeveniment "[${ShortProfileID}/${RunID}] $PreviousCommand"
		TmpTxt="$(mktemp)"
		eval $PreviousCommand > "$TmpTxt" 2>&1
		Result=$?
		InformarEsdeveniment "[${ShortProfileID}/${RunID}] $(cat "$TmpTxt")"
		InformarEsdeveniment "[${ShortProfileID}/${RunID}] Result=${Result}"
		rm "$TmpTxt"
		if [ "$PreviousErrorAbortsMessage" = "" ] ; then Result=0 ; fi
		if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
		if [ $Result -ne 0 ] ; then
			MissatgeSincron "$PreviousErrorAbortsMessage"
			KeepProfileLogs="1"
		fi
	fi
fi
if [ $ResultN -eq 0 ] && [ "$ExecucioDescartada" != "1" ] ; then
	if [ "$(printf '%s' "$VnciFlags" | grep -ie 'w')" ] ; then
		printf '%s' "Waiting for remote VNC client ${VnciHost} to be listening on port TCP/${VnciPort}: "
		while ! Is_RemoteTcpAlive "${VnciHost}:${VnciPort}" 10 1 ; do
			printf '.'
			sleep 10
		done
		printf '%s\n' "Found available."
	fi
	FitxerTestimoni="$(FitxerTestimoniCreat "$ProfileID" "$RunID")"
	if [ $MediaPersistence -ne 0 ] ; then
		ln -s "$FitxerTestimoni" "${DirectoriBase}/${ProfileID}.lock"
	fi
	NoGraphic=""
	QemuDisplaySyntax=0
	if [ "$($QemuBin --help | grep -e '-display sdl' -e '-display gtk')" != "" ] ; then QemuDisplaySyntax=1 ; fi
	if [ "$VisioSDL" = "1" ] ; then
#		NoGraphic=" -nographic"
#	else
		if [ $QemuDisplaySyntax -eq 1 ] ; then
			if [ "$(ls /usr/lib/*/qemu/ui-gtk.so 2>/dev/null)" != "" ] ; then
				NoGraphic="$NoGraphic -display gtk"
			else
				NoGraphic="$NoGraphic -display sdl"
			fi
		else
			NoGraphic="$NoGraphic -sdl"
		fi
		if [ "$(echo ",${DisplayChannels}," | grep -ie ',sdl:noframe,' -ie ',sdl:noquit:noframe,')" != "" ] ; then
			if [ "$(StringWithParameters "$ExtraParameters" "-no-frame")" = "" ] ; then
				if [ $QemuDisplaySyntax -eq 1 ] && [ "$(printf '%s' "$NoGraphic" | grep -e 'sdl')" != "" ] ; then
					NoGraphic="${NoGraphic},frame=off"
				else
					NoGraphic="$NoGraphic -no-frame"
				fi
			fi
		fi
		if [ "$(echo ",${DisplayChannels}," | grep -ie ",sdl:noquit,")" != "" ] || [ "$(echo ",${DisplayChannels}," | grep -ie ",sdl:noframe:noquit,")" != "" ] ; then
			if [ "$(StringWithParameters "$ExtraParameters" "-no-quit")" = "" ] ; then
				NoGraphic="$NoGraphic -no-quit"
			fi
		fi
		if [ "$(echo ",${DisplayChannels}," | grep -ie ",sdl:fullscreen,")" != "" ] || [ "$(echo ",${DisplayChannels}," | grep -ie ",sdl:fullscreen,")" != "" ] ; then
			if [ "$(StringWithParameters "$ExtraParameters" "-full-screen")" = "" ] ; then
				NoGraphic="$NoGraphic -full-screen"
			fi
		fi
	fi
	if [ "$(echo ",${DisplayChannels}," | grep -ie ",curses,")" != "" ] ; then
		if [ "$(StringWithParameters "$ExtraParameters" '-curses' '-display curses')" = "" ] ; then
			if [ $QemuDisplaySyntax -eq 1 ] ; then
				NoGraphic="$NoGraphic -display curses"
			else
				NoGraphic="$NoGraphic -curses"
			fi
			if [ "$(StringWithParameters "$ExtraParameters" "-")" = "" ] ; then
				# Sometimes, with curses output inside screen, en-us works for spanish keyboards.
				NoGraphic="$NoGraphic -k en-us"
			fi
		fi
	fi
	if [ "$DisplayChannels" = "" ] ; then
		if [ "$(StringWithParameters "$ExtraParameters" "-nographic")" = "" ] ; then
			NoGraphic=" -nographic"
		fi
	fi
	if [ "$(echo "$DisplayChannels" | grep -ie "^none$")" != "" ] ; then
		if [ "$(StringWithParameters "$ExtraParameters" "-nographic")" = "" ] ; then
			NoGraphic=" -vga none"
		fi
	fi
#	if [ "$(echo ",${DisplayChannels}," | grep -ie ",vnci,")" != "" ] ; then
#		if [ "$SistemaVirtualitza" = "" ] ; then
#			MissatgeAssincron "La maquina virtual s'esta engegant, i trigara uns minuts en fer-se visible."
#		else
#			MissatgeAssincron "La maquina virtual s'esta engegant, i trigara mig minut en fer-se visible."
#		fi
#	fi
	if [ "$HostVirtualitza" != "" ] && [ "$SistemaVirtualitza" = "" ] ; then
		if [ ! -f "${HOME}/.matromu_kvm-disabled" ] ; then
#			MissatgeAssincron "Aquest equip pot virtualitzar molt mes rapid si es configura la BIOS."
			if [ "$SessioEscriptori" != "" ] ; then
				xmessage -buttons "Continuar:0,Aturar:130" "Aquest equip pot virtualitzar molt mes rapid si es configura la BIOS."
				Result=$?
			else
				printf '%s\n' "Aquest equip pot virtualitzar molt mes rapid si es configura la BIOS." 1>&2
				printf '%s' "Voleu continuar igualment [s/N] " 1>&2
				Result="$(RespostaLletra)"
				if [ "$Result" = "s" ] || [ "$Result" = "y" ] ; then
					Result=0
				else
					Result=130
				fi
			fi
			if [ $Result -eq 0 ] ; then
				dmesg | grep -ie "KVM.*BIOS" >> "${HOME}/.matromu_kvm-disabled"
			else
				exit $Result
			fi
		fi
	else
		rm -f "${HOME}/.matromu_kvm-disabled"
	fi
	SnapShot=""
	if [ $MediaPersistence -eq 0 ] ; then
		SnapShot=" -snapshot"
	fi
	if [ "$HandyName" != "" ] ; then
		ParametreTitol=" -name \"$HandyName\""
	else
		ParametreTitol=""
	fi
	if [ "$LlansemVisorVnci" = "1" ] ; then
		LlansarVnci
		Result=$? ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
	fi
	if [ "$(StringWithParameters "$ExtraParameters" "-m")" = "" ] ; then
		MemoryParameter=" -m $MemoryQuotaMiB"
		TheMemoriaRamDisponible=$(MemoriaRamDisponible -m)
		if [ $MemoryQuotaMiB -gt $TheMemoriaRamDisponible ] ; then
			if [ "$SessioEscriptori" != "" ] ; then
				echo "$(echo "ADVERTENCIA:" ; echo "La maquina virtual asigna ${MemoryQuotaMiB}MiB de memoria de trabajo pero solo hay ${TheMemoriaRamDisponible}MiB disponibles." ; echo "Confirme si quiere proseguir.")" | xmessage -center -buttons "Lanzar igualmente:102,No lanzar:130" -default "No lanzar" -file -
				Respuesta=$?
				if [ $Respuesta -eq 130 ] ; then
					Result=130 ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
				fi
			else
				printf '%s\n' "W: La maquina virtual asigna ${MemoryQuotaMiB}MiB de memoria de trabajo pero solo hay ${TheMemoriaRamDisponible}MiB disponibles." 1>&2
			fi
		fi
	else
		MemoryParameter=""
	fi
	if [ "$ExtraParameters" != "" ] ; then
		ExtraParameters=" $ExtraParameters"
	fi
	ParametresVncQemu="$(GetParametresVncQemu)"
	if [ "$VncPassword" != "" ] && [ "$ParametresVncQemu" != "" ] ; then
		if [ "$(StringWithParameters "$ExtraParameters" "-serial")" = "" ] ; then
			# "-serial none" when using "-monitor stdio"; to avoid error: "cannot use stdio by multiple character devices" "could not connect serial device to character backend 'stdio'"
			InstruccioQemu="echo \"  change vnc password \\\"$VncPassword\\\"\" | $QemuBin $ParametresPlataforma${MemoryParameter} $ParametreTitol $GlobalNetworkSpec $NoGraphic $SnapShot${ModeKVM} $ParametresDisc $ParametresVncQemu${ExtraParameters} -monitor stdio -serial none"
		else
			InstruccioQemu="echo \"  change vnc password \\\"$VncPassword\\\"\" | $QemuBin $ParametresPlataforma${MemoryParameter} $ParametreTitol $GlobalNetworkSpec $NoGraphic $SnapShot${ModeKVM} $ParametresDisc $ParametresVncQemu${ExtraParameters} -monitor stdio"
		fi
	else
		InstruccioQemu="$QemuBin $ParametresPlataforma${MemoryParameter} $ParametreTitol $GlobalNetworkSpec $NoGraphic $SnapShot${ModeKVM} $ParametresDisc $ParametresVncQemu${ExtraParameters}"
	fi
	MissatgesQ=""
	BitacolaTmp="${FitxerTestimoni}.log"
	rm -f "$BitacolaTmp"
	rm -f "${DirTemp}/matromu/${ProfileID}/${RunID}/result.num"
	if [ "$VncPassword" = "" ] ; then
#		if [ "$SessioEscriptori" != "" ] ; then
#			# Via fitxer
#			RedireccionamentQemu=" >> \"$BitacolaTmp\" 2>&1"
#			PreviesRedireccionament="touch \"$BitacolaTmp\" ; chown :$(id -gn) \"$BitacolaTmp\" ; chmod g+rw \"$BitacolaTmp\""
#		else
#			# En mode CLI no ja pot sortir per terminal
			RedireccionamentQemu=" 2>&1 | tee -a \"$BitacolaTmp\""
			PreviesRedireccionament="touch \"$BitacolaTmp\" ; chown :$(id -gn) \"$BitacolaTmp\" ; chmod g+rw \"$BitacolaTmp\""
#		fi
	else
#		# Filtre per evitar mostrar la contrasenya
#		if [ "$SessioEscriptori" != "" ] ; then
#			# Via fitxer
#			RedireccionamentQemu=" 2>&1 | sed -e 's|change vnc password \\\".*\\\" |change vnc password \\\"*****\\\" |' >> \"$BitacolaTmp\""
#			PreviesRedireccionament="touch \"$BitacolaTmp\" ; chown :$(id -gn) \"$BitacolaTmp\" ; chmod g+rw \"$BitacolaTmp\""
#		else
#			# En mode CLI no ja pot sortir per terminal
			RedireccionamentQemu=" 2>&1 | sed -e 's|change vnc password \\\".*\\\" |change vnc password \\\"*****\\\" |' | tee -a \"$BitacolaTmp\""
			PreviesRedireccionament="touch \"$BitacolaTmp\" ; chown :$(id -gn) \"$BitacolaTmp\" ; chmod g+rw \"$BitacolaTmp\""
#		fi
	fi

#	# Fitxer d'execució de Qemu
#	echo '#!/bin/sh' > "${FitxerTestimoni}.qemu.sh"
##	echo "# Workaround to enlarge PulseAudio buffer and avoid Windows guest sound crackling" >> "${FitxerTestimoni}.qemu.sh"
##	echo "export QEMU_PA_SAMPLES=4096 QEMU_AUDIO_DRV=pa" >> "${FitxerTestimoni}.qemu.sh"
#	echo "${InstruccioQemu}" >> "${FitxerTestimoni}.qemu.sh"
##	echo 'Result=$?' >> "${FitxerTestimoni}.qemu.sh"
##	echo "echo \$Result > \"${DirTemp}/matromu/${ProfileID}/${RunID}/result.num\"" >> "${FitxerTestimoni}.qemu.sh"
##	echo 'exit $Result' >> "${FitxerTestimoni}.qemu.sh"
#	echo 'exit $?' >> "${FitxerTestimoni}.qemu.sh"
#	chmod +x "${FitxerTestimoni}.qemu.sh"

	RespawnCode_Pre=''
	RespawnCode_Post=''
	if [ "$Respawn" = "1" ] ; then
		echo "This is the command to avoid this VM instance respawn: touch \"${ProfileFile}.stop\""
		RespawnCode_Pre="echo \"This is the command to avoid VM respawn: touch \\\"${ProfileFile}.stop\\\"\"
rm -f \"${ProfileFile}.stop\"
while [ ! -f \"${ProfileFile}.stop\" ] ; do
"
		RespawnCode_Post="done
rm -f \"${ProfileFile}.stop\"
"
		RespawnCode_Indentation='	'
	fi
	# Fitxer de gestions per l'execució de Qemu
	echo '#!/bin/sh' > "${FitxerTestimoni}.sh"
	echo 'Result=0' >> "${FitxerTestimoni}.sh"
	echo 'ResultN=0' >> "${FitxerTestimoni}.sh"
	echo '' >> "${FitxerTestimoni}.sh"
	echo 'Is_IntegerNr ()' >> "${FitxerTestimoni}.sh"
	echo '{' >> "${FitxerTestimoni}.sh"
	echo '	local TestValue="$1"' >> "${FitxerTestimoni}.sh"
	echo '	TestValue="$(expr "$TestValue" : "[ ]*\(.*[^ ]\)[ ]*$")"' >> "${FitxerTestimoni}.sh"
	echo '	if [ "$TestValue" = "" ] ; then TestValue="." ; fi' >> "${FitxerTestimoni}.sh"
	echo '	[ "$TestValue" -eq "$TestValue" ] > /dev/null 2>&1' >> "${FitxerTestimoni}.sh"
	echo '	return $?' >> "${FitxerTestimoni}.sh"
	echo '}' >> "${FitxerTestimoni}.sh"
	echo 'Instruccions_PreviesXarxa ()' >> "${FitxerTestimoni}.sh"
	echo '{' >> "${FitxerTestimoni}.sh"
	echo '	local Result=0' >> "${FitxerTestimoni}.sh"
	echo '	local ResultN=0' >> "${FitxerTestimoni}.sh"
	echo "$PreviesXarxa" | grep -ve '^$' >> "${FitxerTestimoni}.sh"
	echo "	echo \$ResultN > \"${DirTemp}/matromu/${ProfileID}/${RunID}/result_part.num\"" >> "${FitxerTestimoni}.sh"
	echo '}' >> "${FitxerTestimoni}.sh"
	echo '' >> "${FitxerTestimoni}.sh"
	echo 'Instruccions_Qemu ()' >> "${FitxerTestimoni}.sh"
	echo '{' >> "${FitxerTestimoni}.sh"
	echo '	local Result=0' >> "${FitxerTestimoni}.sh"
	echo '	local ResultN=0' >> "${FitxerTestimoni}.sh"
#	echo "	${PrefixQemu}\"${FitxerTestimoni}.qemu.sh\"" >> "${FitxerTestimoni}.sh"
#	echo '	if [ $ResultN -eq 0 ] ; then' >> "${FitxerTestimoni}.sh"
#	echo "	${PrefixQemu}${InstruccioQemu}" >> "${FitxerTestimoni}.sh"
	if [ "$(StringWithParameters "$InstruccioQemu" '-curses' '-display curses')" != "" ] ; then
		if Is_Executable screen ; then
			echo '#!/bin/sh' > "${FitxerTestimoni}.screen.sh"
			if [ "$DISPLAY" != "" ] ; then
				echo "	export DISPLAY=\"${DISPLAY}\"" >> "${FitxerTestimoni}.screen.sh"
			fi
			printf '%s' "$RespawnCode_Pre" >> "${FitxerTestimoni}.screen.sh"
			echo "${RespawnCode_Indentation}echo '$' ${PrefixQemu}$InstruccioQemu" >> "${FitxerTestimoni}.screen.sh"
			echo "${RespawnCode_Indentation}${PrefixQemu}$InstruccioQemu" >> "${FitxerTestimoni}.screen.sh"
			echo "${RespawnCode_Indentation}Result=\$?" >> "${FitxerTestimoni}.screen.sh"
			echo "${RespawnCode_Indentation}echo Qemu exitcode: \$Result" >> "${FitxerTestimoni}.screen.sh"
			printf '%s' "$RespawnCode_Post" >> "${FitxerTestimoni}.screen.sh"
			echo 'exit $Result' >> "${FitxerTestimoni}.screen.sh"
			chmod u+x "${FitxerTestimoni}.screen.sh"
#			echo '	if [ "$TERM" = "" ] ; then export TERM=xterm-256color ; fi' >> "${FitxerTestimoni}.sh"
			ProfileName="$(printf '%s' "$ProfileFile" | tr -s '/' '\n' | tail -n 1 | cut -f 1 -d '.')"
			echo "	echo '$' \"screen -D -m -S '${ProfileName}-qemu-${RunID}' -L -Logfile '${FitxerTestimoni}.screen.log' '${FitxerTestimoni}.screen.sh'\"" >> "${FitxerTestimoni}.sh"
			echo "	screen -D -m -S '${ProfileName}-qemu-${RunID}' -L -Logfile '${FitxerTestimoni}.screen.log' '${FitxerTestimoni}.screen.sh'" >> "${FitxerTestimoni}.sh"
			echo "	Result=\"\$(cat \"${FitxerTestimoni}.screen.log\" | tail -n 1 | cut -f 2 -d ':' | cut -f 2 -d '=' | cut -f 2 -d ' ')\"" >> "${FitxerTestimoni}.sh"
			echo '	if ! Is_IntegerNr $Result ; then Result=96 ; fi' >> "${FitxerTestimoni}.sh"
			echo '	if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi' >> "${FitxerTestimoni}.sh"
#			echo "	cat \"${FitxerTestimoni}.screen.log\"" >> "${FitxerTestimoni}.sh"  DIALOG SCREENS PRODUCE TERMINAL FLICKERING AND CODES GARBAGE. PENDING TO DISCOVER HOW TO FILTER THIS.
		else
			printf '%s\n' "W: Utility screen not found to allow curses output to terminal." | tee -a "$BitacolaTmp" 1>&2
			if [ "$DISPLAY" != "" ] ; then
				echo "	export DISPLAY=\"${DISPLAY}\"" >> "${FitxerTestimoni}.sh"
			fi
			printf '%s' "$RespawnCode_Pre" >> "${FitxerTestimoni}.sh"
			echo "	${RespawnCode_Indentation}echo '$' ${PrefixQemu}${InstruccioQemu}" >> "${FitxerTestimoni}.sh"
			echo "	${RespawnCode_Indentation}${PrefixQemu}${InstruccioQemu}" >> "${FitxerTestimoni}.sh"
			echo "	${RespawnCode_Indentation}Result=\$? ; if [ \$ResultN -eq 0 ] ; then ResultN=\$Result ; fi" >> "${FitxerTestimoni}.sh"
			echo "	${RespawnCode_Indentation}echo Qemu exitcode: \$Result" >> "${FitxerTestimoni}.sh"
			printf '%s' "$RespawnCode_Post" >> "${FitxerTestimoni}.sh"
		fi
	else
		if [ "$DISPLAY" != "" ] ; then
			echo "	export DISPLAY=\"${DISPLAY}\"" >> "${FitxerTestimoni}.sh"
		fi
		printf '%s' "$RespawnCode_Pre" >> "${FitxerTestimoni}.sh"
		echo "	${RespawnCode_Indentation}echo '$' \"$(printf '%s' "${PrefixQemu}${InstruccioQemu}" | sed -e 's|"|\\"|g')\"" >> "${FitxerTestimoni}.sh"
		echo "	${RespawnCode_Indentation}${PrefixQemu}${InstruccioQemu}" >> "${FitxerTestimoni}.sh"
		echo "	${RespawnCode_Indentation}Result=\$? ; if [ \$ResultN -eq 0 ] ; then ResultN=\$Result ; fi" >> "${FitxerTestimoni}.sh"
		echo "	${RespawnCode_Indentation}echo Qemu exitcode: \$Result" >> "${FitxerTestimoni}.sh"
		printf '%s' "$RespawnCode_Post" >> "${FitxerTestimoni}.sh"
	fi
#	echo '	fi' >> "${FitxerTestimoni}.sh"
	echo "	echo \$ResultN > \"${DirTemp}/matromu/${ProfileID}/${RunID}/result_part.num\"" >> "${FitxerTestimoni}.sh"
	echo '}' >> "${FitxerTestimoni}.sh"
	echo '' >> "${FitxerTestimoni}.sh"
	echo 'Instruccions_PosteriorsXarxa ()' >> "${FitxerTestimoni}.sh"
	echo '{' >> "${FitxerTestimoni}.sh"
	echo '	local Result=0' >> "${FitxerTestimoni}.sh"
	echo '	local ResultN=0' >> "${FitxerTestimoni}.sh"
	echo "$PosteriorsXarxa" >> "${FitxerTestimoni}.sh"
	echo "	echo \$ResultN > \"${DirTemp}/matromu/${ProfileID}/${RunID}/result_part.num\"" >> "${FitxerTestimoni}.sh"
	echo '}' >> "${FitxerTestimoni}.sh"
	echo '' >> "${FitxerTestimoni}.sh"
	echo "cd \"$(dirname "$ProfileFile")\"" >> "${FitxerTestimoni}.sh"
	echo "echo \"\$(date +'%F %T') Launching VM ${ShortProfileID}/${RunID}\"" >> "${FitxerTestimoni}.sh"
	echo "$PreviesRedireccionament" >> "${FitxerTestimoni}.sh"
	echo "Instruccions_PreviesXarxa${RedireccionamentQemu}" >> "${FitxerTestimoni}.sh"
	echo "Result=\$(cat \"${DirTemp}/matromu/${ProfileID}/${RunID}/result_part.num\")" >> "${FitxerTestimoni}.sh"
	echo 'if ! Is_IntegerNr $Result ; then Result=96 ; fi' >> "${FitxerTestimoni}.sh"
	echo 'if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi' >> "${FitxerTestimoni}.sh"
	if [ "$(StringWithParameters "$InstruccioQemu" '-curses' '-display curses')" != "" ] ; then
		if Is_Executable screen ; then
			echo "Instruccions_Qemu" >> "${FitxerTestimoni}.sh"
#			echo 'Result=$?' >> "${FitxerTestimoni}.sh"
			echo "Result=\$(cat \"${DirTemp}/matromu/${ProfileID}/${RunID}/result_part.num\")" >> "${FitxerTestimoni}.sh"
			echo 'if ! Is_IntegerNr $Result ; then Result=96 ; fi' >> "${FitxerTestimoni}.sh"
			echo 'if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi' >> "${FitxerTestimoni}.sh"
			echo 'if [ $Result -ne 0 ] ; then' >> "${FitxerTestimoni}.sh"
			echo "	cat \"${FitxerTestimoni}.screen.log\" >> \"$BitacolaTmp\"" >> "${FitxerTestimoni}.sh"
			echo 'fi' >> "${FitxerTestimoni}.sh"
		else
			echo "Instruccions_Qemu${RedireccionamentQemu}" >> "${FitxerTestimoni}.sh"
			echo "Result=\$(cat \"${DirTemp}/matromu/${ProfileID}/${RunID}/result_part.num\")" >> "${FitxerTestimoni}.sh"
			echo 'if ! Is_IntegerNr $Result ; then Result=96 ; fi' >> "${FitxerTestimoni}.sh"
			echo 'if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi' >> "${FitxerTestimoni}.sh"
		fi
	else
		echo "Instruccions_Qemu${RedireccionamentQemu}" >> "${FitxerTestimoni}.sh"
		echo "Result=\$(cat \"${DirTemp}/matromu/${ProfileID}/${RunID}/result_part.num\")" >> "${FitxerTestimoni}.sh"
		echo 'if ! Is_IntegerNr $Result ; then Result=96 ; fi' >> "${FitxerTestimoni}.sh"
		echo 'if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi' >> "${FitxerTestimoni}.sh"
	fi
	echo "Instruccions_PosteriorsXarxa${RedireccionamentQemu}" >> "${FitxerTestimoni}.sh"
	echo "Result=\$(cat \"${DirTemp}/matromu/${ProfileID}/${RunID}/result_part.num\")" >> "${FitxerTestimoni}.sh"
	echo 'if ! Is_IntegerNr $Result ; then Result=96 ; fi' >> "${FitxerTestimoni}.sh"
	echo 'if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi' >> "${FitxerTestimoni}.sh"
	echo "rm -f \"$FitxerTestimoni\"" >> "${FitxerTestimoni}.sh"
	echo "rm -f \"${DirectoriBase}/${ProfileID}.lock\"" >> "${FitxerTestimoni}.sh"
#	echo "Result=\$(cat \"${DirTemp}/matromu/${ProfileID}/${RunID}/result.num\")" >> "${FitxerTestimoni}.sh"
#	echo 'if ! Is_IntegerNr $Result ; then Result=96 ; fi' >> "${FitxerTestimoni}.sh"
#	echo 'Result=$? ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi' >> "${FitxerTestimoni}.sh"
#	echo "echo \$Result > \"${DirTemp}/matromu/${ProfileID}/${RunID}/result.num\"" >> "${FitxerTestimoni}.sh"
#	echo "chown :$(id -gn) \"${DirTemp}/matromu/${ProfileID}/${RunID}/result.num\" ; chmod g+rw \"${DirTemp}/matromu/${ProfileID}/${RunID}/result.num\"" >> "${FitxerTestimoni}.sh"
	echo "echo \"\$(date +'%F %T') VM ${ShortProfileID}/${RunID} ended with exitcode \$Result\"" >> "${FitxerTestimoni}.sh"
	echo "echo \$ResultN > \"${DirTemp}/matromu/${ProfileID}/${RunID}/result.num\"" >> "${FitxerTestimoni}.sh"
	echo 'exit $ResultN' >> "${FitxerTestimoni}.sh"
	chmod +x "${FitxerTestimoni}.sh"
	
	InformarEsdeveniment "[${ShortProfileID}/${RunID}] ${AmbPrefixSudo}"
	if [ "$PreviesXarxa" != "" ] ; then
#		InformarEsdeveniment "[${ShortProfileID}/${RunID}] \$ ${AmbPrefixSudo}${PreviesXarxa}"
		InformarEsdeveniment "[${ShortProfileID}/${RunID}] \$\$ Instruccions_PreviesXarxa"
	fi
	if [ "$VncPassword" = "" ] ; then
		InformarEsdeveniment "[${ShortProfileID}/${RunID}] \$ ${PrefixQemu}${InstruccioQemu}"
	else
		InformarEsdeveniment "[${ShortProfileID}/${RunID}] \$ ${PrefixQemu}echo '  change vnc password \"*****\"' |$(echo "$InstruccioQemu" | cut -f 2- -d '|')"
	fi
	export matromu_vncpwd="$VncPassword"
	if [ "$DISPLAY" != "" ] && [ "$AmbPrefixSudo" != "" ] ; then
		if Is_Executable xhost ; then
			xhost +si:localuser:root
		else
			printf '%s\n' "W: xhost not found to allow root to make connections to the X server." 1>&2
		fi
	fi
	if [ "$LlansemVisorVncd" = "1" ] ; then
		if Is_Executable "$SSD" ; then
			echo '$' ${AmbPrefixSudo}$SSD --pidfile "${DirectoriBase}/${ProfileID}.pid" --background --start --startas "${FitxerTestimoni}.sh" --
			${AmbPrefixSudo}$SSD --pidfile "${DirectoriBase}/${ProfileID}.pid" --background --start --startas "${FitxerTestimoni}.sh" --
			ResultQ=$?
		else
#			echo 'if [ "$TERM" = "" ] ; then export TERM=xterm-256color ; fi' >> "${FitxerTestimoni}.sh"
			echo '$' ${AmbPrefixSudo}env matromu_vncpwd="$VncPassword" screen -S "${ProfileName}-matromu" -d -m "${FitxerTestimoni}.sh"
			${AmbPrefixSudo}env matromu_vncpwd="$VncPassword" screen -S "${ProfileName}-matromu" -d -m "${FitxerTestimoni}.sh"
			ResultQ=$?
		fi
		Result=$ResultQ ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
	else
		echo '$' ${AmbPrefixSudo}"${FitxerTestimoni}.sh"
		${AmbPrefixSudo}"${FitxerTestimoni}.sh"
		ResultQ=$?
		Result=$ResultQ ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
	fi
	export matromu_vncpwd=
	if [ -f "${DirTemp}/matromu/${ProfileID}/${RunID}/result.num" ] ; then
		ResultQ=$(cat "${DirTemp}/matromu/${ProfileID}/${RunID}/result.num")
		if ! Is_IntegerNr $ResultQ ; then ResultQ=96 ; fi
		Result=$ResultQ ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
		rm -f "${DirTemp}/matromu/${ProfileID}/${RunID}/result.num"
	fi
	if [ $ResultN -eq 0 ] && [ "$LlansemVisorVncd" = "1" ] ; then
		# En mode servidor (matromus) es pot especificar vnc sense requerir escriptori.
		LlansarVncDirecte "${DirTemp}/matromu/${ProfileID}/${RunID}/result.num"
		Result=$? ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
		# En aquest punt, si després d'un segon el procés concret de Qemu encara
		# està corrent, caldria oferir reconnectar-hi.
	fi
	if [ -f "$BitacolaTmp" ] ; then
		MissatgesQ="$(cat "$BitacolaTmp")"
		#cat "$BitacolaTmp" | tee -a "$BitacoraPerfil"
		cat "$BitacolaTmp" | tee -a "$BitacoraPerfil" >/dev/null
		if [ $ResultN -eq 0 ] ; then rm -f "$BitacolaTmp" ; fi
#		InformarEsdeveniment "[${ShortProfileID}/${RunID}] $MissatgesQ"
	fi
	if [ "$LlansemVisorVnci" = "1" ] && [ "$VncJaEstava" != "1" ] ; then
		MatarVNC
	fi
	rmdir --ignore-fail-on-non-empty --parents "$(dirname "$FitxerTestimoni")" 2>/dev/null
	if [ -f "${DirTemp}/matromu/${ProfileID}/${RunID}/result.num" ] ; then
		ResultQ=$(cat "${DirTemp}/matromu/${ProfileID}/${RunID}/result.num")
		if ! Is_IntegerNr $ResultQ ; then ResultQ=96 ; fi
		Result=$ResultQ ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
	fi
	if [ $ResultN -eq 0 ] ; then
		# On background fork, this is inconvenient;
echo		rm -f "${DirTemp}/matromu/${ProfileID}/${RunID}/result.num"
echo		rm -f "${FitxerTestimoni}.sh"
#		rm -f "${FitxerTestimoni}.qemu.sh"
	else
#		InformarEsdeveniment "[${ShortProfileID}/${RunID}] Left caller scripts to debug: ${FitxerTestimoni}.sh ${FitxerTestimoni}.qemu.sh"
		InformarEsdeveniment "[${ShortProfileID}/${RunID}] Left caller scripts to debug: ${FitxerTestimoni}.sh"
	fi
#	InformarEsdeveniment "[${ShortProfileID}/${RunID}] ResultQ=${ResultQ}"
	if [ $ResultQ -ne 0 ] ; then
		if [ "$MissatgesQ" = "" ] ; then
			MissatgesQ="PROBLEMA: La virtualitzacio ha finalitzat amb codi $ResultQ."
		else
			if [ "$(echo "$MissatgesQ" | grep -ie 'Permission denied')" != "" ] ; then
				if [ "$(echo "$MissatgesQ" | grep -ie 'VNC.*on.*:-')" != "" ] ; then
					MissatgesQ="$(echo "PROBLEMA: La virtualitzacio ha finalitzat amb codi $ResultQ."; echo "$MissatgesQ"; echo "SOLUCIO: Utilitzeu un port major de 1023 per VNC, o establiu SuperuserOnly=1" ; echo "a la configuracio del perfil: $ProfileFile")"	#'
				else
					MissatgesQ="$(echo "PROBLEMA: La virtualitzacio ha finalitzat amb codi $ResultQ."; echo "$MissatgesQ"; echo "SOLUCIO: Doneu permisos a l'usuari pel recurs o fitxers, o establiu SuperuserOnly=1" ; echo "a la configuracio del perfil: $ProfileFile")"	#'
				fi
			else
				MissatgesQ="$(echo "PROBLEMA: La virtualitzacio ha finalitzat amb codi $ResultQ."; echo "$MissatgesQ" ; echo "F.PERFIL: $ProfileFile")"
			fi
		fi
		KeepProfileLogs="1"
		MissatgeSincron "$MissatgesQ"
	else
		if [ "$VisioVncInvers" = "1" ] ; then
			MissatgeSincron "La sessio de maquina virtual ha finalitzat."
		fi
	fi
	if [ "$PosteriorCommand" != "" ] ; then
		InformarEsdeveniment "[${ShortProfileID}/${RunID}] $PosteriorCommand"
		TmpTxt="$(mktemp)"
		$PosteriorCommand > "$TmpTxt" 2>&1
		Result=$? ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
		InformarEsdeveniment "[${ShortProfileID}/${RunID}] (Result=${Result}) $(cat "$TmpTxt")"
		rm "$TmpTxt"
	fi
fi
#InformarEsdeveniment "[${ShortProfileID}/${RunID}] ResultN=${ResultN}"
if [ -f "$BitacoraPerfil" ] && [ "$ExecucioDescartada" != "1" ] ; then
#	if [ "$(cat "$BitacoraPerfil")" != "" ] ; then
#		cat "$BitacoraPerfil"
#	fi
	if [ "$KeepProfileLogs" != "1" ] && [ $ResultN -eq 0 ] ; then
		rm "$BitacoraPerfil"
	fi
fi
cd "$DirectorioPrevio"
#if [ -f "${ProfileFile}.stop" ] ; then Respawn="0" ; fi
# MAD STRATEGY; DISABLED FEATURE:
#if [ "$Respawn" = "1" ] && [ $ResultQ -eq 0 ] ; then
#	"$0" "$@" >> /tmp/prova1.log 2>&1
#	Result=$? ; if [ $ResultN -eq 0 ] ; then ResultN=$Result ; fi
#fi
if [ "$NozeroStatusToFile" != "" ] && [ ! -f "$NozeroStatusToFile" ] && [ $StatusCode -ne 0 ] ; then echo $StatusCode > "$NozeroStatusToFile" ; fi
exit $ResultN
