diff --git a/config/inc_projects_config.php b/config/inc_projects_config.php
deleted file mode 100644
index 926ce3cd6d9bd303a29dbfb00fbb4a4abd642d0a..0000000000000000000000000000000000000000
--- a/config/inc_projects_config.php
+++ /dev/null
@@ -1,118 +0,0 @@
-<?php
-
-// ----------------------------------------------------------------------
-// fetch status infos von den einzelnen Phasen
-// ----------------------------------------------------------------------
-
-$aConfig = array(
-    // Basispfad:
-    'workDir' => '/var/imldeployment',
-    'tmpDir' => '/var/tmp/imldeployment',
-    'versionsToKeep' => 10, // for cleanup: keep n unused versions
-    'builtsToKeep' => 3, // for cleanup: keep n failed builds
-    'hooks' => array(
-        'build-postclone' => 'hooks/onbuild-postclone',
-        'build-precompress' => 'hooks/onbuild', // TODO: remove this
-    ),
-    'lang' => 'de', // for available languages see ./config/lang/*.json
-    // rsync of archives
-    'mirrorPackages' => array(),
-    // ssh install - if a host is given
-    'installPackages' => array(
-        'user' => 'imldeployment',
-        
-        // command to update ssh hostkey in known_hosts file
-        // %s is name of the server (2x)
-        'addkeycommand' => '/usr/bin/ssh-keygen -R %s; /usr/bin/ssh-keyscan -t rsa %s >> /home/www-data/.ssh/known_hosts',
-        
-        // command to verify if puppet host is correct
-        'testcommand' => 'sudo puppet --version',
-        
-        // puppet agent liefert 0 oder 2 zurueck, wenn OK
-        // http://docs.puppetlabs.com/references/3.4.0/man/apply.html
-        'command' => 'sudo puppet agent -t --detailed-exitcodes ; rc=$?; if [ $rc -eq 2 ]; then rc=0; fi ; exit $rc',
-    ),
-    'phases' => array(
-        "preview" => array(
-            'css' => array(
-                'bgdark' => 'background:#89a; color:#f8f8f8;',
-                'bglight' => 'background:#e8e8f8; color:#333; background: rgba(180,180,230, 0.3);',
-                'bgbutton' => 'background:#89a; color:#fcfcfc; border: 1px solid rgba(0,0,0,0.15);',
-            ),
-        ),
-        "stage" => array(
-            'css' => array(
-                'bgdark' => 'background:#8aa; color:#f8f8f8;',
-                'bglight' => 'background:#e4f8f8; color:#333; background: rgba(180,210,210, 0.3);',
-                'bgbutton' => 'background:#8aa; color:#fcfcfc; border: 1px solid rgba(0,0,0,0.15);',
-            ),
-        ),
-        "live" => array(
-            'css' => array(
-                'bgdark' => 'background:#8a8; color:#f8f8f8;',
-                'bglight' => 'background:#e0f8e0; color:#333; background: rgba(180,250,180, 0.3);',
-                'bgbutton' => 'background:#8a8; color:#fcfcfc; border: 1px solid rgba(0,0,0,0.15);',
-            ),
-            // wenn deploytimes existiert, dann wird nach dem Deploy das Paket 
-            // in einer Queue zurueckgehalten
-            "deploytimes" => array('/(Mon|Tue|Wed|Thu)\ 14\:/'),
-        ),
-    ),
-    'showdebug' => array(
-        'ip'=>array('10.0.2.2', '127.0.0.1', '130.92.79.49'),
-    ), // for available languages see ./config/lang/*.json
-);
-
-// ----------------------------------------------------------------------
-// override for local development
-// ----------------------------------------------------------------------
-
-
-switch (php_uname("n")) {
-    case "USER":
-    case "AAE49":
-    case "dev.ci.iml.unibe.ch":
-        $aConfig['workDir'] = "D:\imldeployment";
-        break;
-
-    case "ci.iml.unibe.ch":
-
-        // synch der Pakete nur auf dem Livesystem
-        $aConfig['mirrorPackages'] = array(
-            'puppet' => array(
-                'type' => 'rsync',
-                'runas' => 'www-data', // nur fuer commandline
-                'target' => 'ladmin@calcium.iml.unibe.ch:/share/imldeployment',
-            ),
-            'puppet.one' => array(
-                'type' => 'rsync',
-                'runas' => 'www-data', // nur fuer commandline
-                'target' => 'copy-deployment@puppet.one.iml.unibe.ch:/var/shared/imldeployment',
-            ),
-        );
-        break;
-
-    default:
-        break;
-}
-if (!array_key_exists('tmpDir', $aConfig) || !$aConfig["tmpDir"]){
-    $aConfig["tmpDir"] = (getenv("temp") ? getenv("temp") : "/var/tmp") . '/imldeployment';
-}
-// ----------------------------------------------------------------------
-// TODO: include custom settings that were saved in the GUI
-// ----------------------------------------------------------------------
-
-
-// ----------------------------------------------------------------------
-// generate some vars
-// ----------------------------------------------------------------------
-
-$aConfig = array_merge($aConfig, array(
-    'appRootDir' => dirname(dirname(__FILE__)),
-    'configDir' => dirname(__FILE__),
-    'dataDir' => $aConfig['workDir'] . '/data',    // to write data: ssh keys, projects, database
-    'buildDir' => $aConfig['workDir'] . '/build',
-    'buildDefaultsDir' => $aConfig['workDir'] . '/defaults',
-    'packageDir' => $aConfig['workDir'] . '/packages',
-    'archiveDir' => $aConfig['workDir'] . '/packages/_files',
-        ));
diff --git a/config/lang/de.json b/config/lang/de.json
index 8eb22a043914edb6fd9a4ddebe47a5d98b22064f..c2edacd85be49f6cb187af326eca678176db8f67 100644
--- a/config/lang/de.json
+++ b/config/lang/de.json
@@ -1,8 +1,10 @@
 {
     
+    "menu": "Men&uuml;",
     "menu-brand": "Deployment GUI",
     "menu-overview": "&Uuml;bersicht",
     "menu-projects": "Projekte",
+    "menu-checklang": "Vergleich Sprachtexte",
     "menu-settings": "Einstellungen",
     "menu-logs": "Logs",
     "menu-new-project": "Neues Projekt anlegen",
@@ -20,6 +22,7 @@
     
     "overview-label": "&Uuml;bersicht",
     "overview-hint":"Alle Projekte und Versionen in den einzelnen Phasen",
+    "overview-hint-dblclick":"Doppelklick um das Projekt [%s] zu &ouml;ffnen",
     "overview-filter":"Filter",
     "overview-filter-hint":"in der erweiterten Ansicht nur dieses Projekt anzeigen",
     "overview-simpleview":"zur einfachen Ansicht",
@@ -218,14 +221,17 @@
     "build-type": "Build Typ",
     "commitmessage": "Commit-Message",
     "change": "Wechseln",
+    "cleanup": "Cleanup",
     "contact": "Kontakt",
     "creating-directory": "Lege das Verzeichnis %s an.",
     "creating-file": "Lege Datei %s an.",
     "defaultbranch": "[default: Master oder Trunk]",
+    "defaults-all-phases": "Default-Werte (f&uuml;r alle Phasen)",
+    "delete": "L&ouml;schen",
     "deploy": "Deploy",
     "deploy-hint": "Deploy der Queue von Phase [%s]",
     "deploy-impossible": "Deploy der Queue von Phase [%s] ist nicht m&ouml;glich.",
-    "deploy-settings": "Deployment - Einstellungen",
+    "deploy-settings": "Deployment-Einstellungen",
     "deploytimes": "Deployment Zeitpunkte",
     "deploytimes-immediately": "Ein Archiv in der Queue wird sofort ins Repo gestellt.",
     "deploymethod": "Deployment-Methode",
@@ -237,6 +243,7 @@
     "dir-archive": "Archiv-Verzeichnis",
     "dir-cache": "Cache-Verzeichnis",
     "dir-builds": "Build-Verzeichnis",
+    "edit": "Bearbeiten",
     "empty": "[leer]",
     "error": "FEHLER",
     "error-no-phase": "Es wurde keine Phase mitgegeben.",
@@ -245,7 +252,19 @@
     "fileprefix": "File Prefix",
     "fileprefix-label": "File-Prefix <span class=\"error\"><br>Nach dem ersten Build nicht mehr änderbar!</span>",
     "finished": "Beendet",
+    "foreman-error-missing-template": "In Foreman wurde das Templatefile [%s] definiert, aber dieses existiert nicht im Build.",
+    "foreman-error-no-replacement-for-id": "In Foreman wurde keine noch Ersetzung f&uuml;r [%s] definiert.",
+    "foreman-error-no-target": "In Foreman wurde keine Ziel-Datei definiert",
+    "foreman-error-no-replacement-in-templatefile": "Es wurde kein Platzhalter zum Ersetzen in diesem Template gefunden.",
+    "foreman-error-template-unknown": "Das Template wurde in Foreman nicht aufgenommen",
+    "foreman-error-replacement-unknown": "Das Replacement [%s] in Foreman existiert im Template nicht.",
+    "foreman-hostgroup": "Foreman Hostgruppe",
+    "foreman-hostgroup-override": "Foreman Hostgruppe (override)",
+    "foreman-hostgroup-id": "Foreman Hostgruppe (%s)",
+    "foreman-no-host": "Es wurde kein Host in Foreman konfiguriert. Es werden die Platzhalter in Templates erkannt, aber nicht deren Ziel und Ersetzungen.",
+    "foreman-targetfile": "Name der Zieldatei",
     "gotop": "Seitenanfang",
+    "host": "Host",
     "hosts": "Hosts",
     "hostname4puppet": "Hostname f&uuml;r Puppet Agent",
     "inactive": "inaktiv",
@@ -253,11 +272,14 @@
     "infos": "Infos",
     "login": "Anmelden",
     "logoff": "Abmelden",
-    "ok": "OK",
+    "messenger": "Benachrichtigungen",
+    "messenger-email": "Email-Adressen",
+    "messenger-slack": "Slack WebHook",
     "new-project": "neues Projekt",
     "new-project-hint": "ein neues Projekt anlegen",
     "no": "nein",
     "none": "kein(e)",
+    "ok": "OK",
     "packages": "Pakete",
     "phase": "Phase",
     "phase-details": "Details",
@@ -266,15 +288,16 @@
     "phase-targethosts": "Zielsysteme",
     "phases": "Phasen",
     "project": "Projekt",
+    "project-home": "Projekt Startseite",
     "projectdescription": "Kurzbeschreibung",
     "projectname": "Projektname",
     "projectmanager": "Projektleiter",
     "queue": "Queue",
+    "raw-data": "Raw data",
     "replacement-fields": "erkannte Platzhalter:",
     "replacement-fields-not-found": "Es wurden keine Platzhalter im Format <em>@replace[&quot;Name&quot;]</em> im Template gefunden.",
     "replacement-targetfile": "Ziel-Datei",
     "replacements": "Ersetzungen mit Template-Dateien",
-    "replacements-info": "Beim Build-Prozess gefundene Templates werden aufgelistet und darin vorhandene Platzhalter erkannt. Die Felder sind ausschliesslich für die neue Infrastruktur relevant.",
     "repositoryinfos": "Quell-Repository",
     "repository-access-browser": "Browserzugriff auf das Repo",
     "repository-auth": "Authentifizierung/ Dateiname zum SSH-Private-Key",
diff --git a/config/lang/en.json b/config/lang/en.json
index dcdee60ff5d07827840426fed5627d61a42e8606..f3bcd4dac9f15d40b9102f0a0ccf5ca00380bb55 100644
--- a/config/lang/en.json
+++ b/config/lang/en.json
@@ -1,7 +1,9 @@
 {
+    "menu": "Menu",
     "menu-brand": "IML Deployment GUI",
     "menu-overview": "back to overview",
     "menu-projects": "Projects",
+    "menu-checklang": "Compare language texts",
     "menu-settings": "Settings",
     "menu-logs": "Logs",
     "menu-new-project": "Create new project",
@@ -19,6 +21,7 @@
     
     "overview-label": "Overview",
     "overview-hint":"all projects and versions in all phases",
+    "overview-hint-dblclick":"Double click to open the project [%s]",
     "overview-filter":"Filter",
     "overview-filter-hint":"Show only this project in the extended view",
     "overview-simpleview":"Show simple view",
@@ -221,13 +224,16 @@
     "change": "Change",
     "commitmessage": "Commit message",
     "contact": "contact",
+    "cleanup": "Cleanup",
     "creating-directory": "Creating directory %s",
     "creating-file": "Creating file %s",
     "defaultbranch": "[default: master or trunk]",
+    "defaults-all-phases": "Default values (for all phases)",
+    "delete": "Delete",
     "deploy": "Deploy",
     "deploy-hint": "Deploy queue of phase [%s]",
     "deploy-impossible": "Deploy queue of phase [%s] is not possible.",
-    "deploy-settings": "Deployment - settings",
+    "deploy-settings": "Deployment settings",
     "deploymethod": "Deployment method",
     "deploymethod-none": "None. Do not trigger any action.",
     "deploymethod-puppet": "Run Puppet on target host(s)",
@@ -239,6 +245,7 @@
     "dir-archive": "Archive directory",
     "dir-cache": "Cache directory",
     "dir-builds": "Build directory",
+    "edit": "Edit",
     "empty": "[empty]",
     "error": "ERROR",
     "error-no-phase": "There no phase was given as parameter.",
@@ -247,7 +254,19 @@
     "fileprefix": "File prefix",
     "fileprefix-label": "File prefix <span class=\"error\"><br>It cannot be changed after the first build!</span>",
     "finished": "Fisnished",
+    "foreman-error-missing-template": "In Foreman the templatefile [%s] was defined but it does not exist in the build.",
+    "foreman-error-no-replacement-for-id": "There is no replacement for [%s] in Foreman.",
+    "foreman-error-no-target": "No target file was set in Foreman",
+    "foreman-error-no-replacement-in-templatefile": "No placeholder for a replacement was found in this template.",
+    "foreman-error-template-unknown": "The template was not added in Foreman.",
+    "foreman-error-replacement-unknown": "The replacement [%s] from Foreman has no plceholder in the template file.",
+    "foreman-hostgroup": "Foreman hostgroup",
+    "foreman-hostgroup-override": "Foreman Hostgroup (override)",
+    "foreman-hostgroup-id": "Foreman Hostgroup (%s)",
+    "foreman-no-host": "No host was configured in Foreman.",
+    "foreman-targetfile": "Target file",
     "gotop": "top",
+    "host": "Host",
     "hosts": "Hosts",
     "hostname4puppet": "Hostname to start puppet agent",
     "inactive": "inactive",
@@ -255,11 +274,14 @@
     "infos": "Infos",
     "login": "Login",
     "logoff": "Logoff",
-    "ok": "OK",
+    "messenger": "Messenger/ notifications",
+    "messenger-email": "Email",
+    "messenger-slack": "Slack",
     "new-project": "new project",
     "new-project-hint": "create a new project",
     "no": "no",
     "none": "none",
+    "ok": "OK",
     "packages": "packages",
     "phase": "Phase",
     "phase-details": "Details",
@@ -268,15 +290,16 @@
     "phase-targethosts": "Target hosts",
     "phases": "Phases",
     "project": "Project",
+    "project-home": "Projekt home",
     "projectdescription": "Short description",
     "projectname": "Project name",
     "projectmanager": "Projekt manager",
     "queue": "Queue",
+    "raw-data": "Raw data",
     "replacement-fields": "Detected placeholders:",
     "replacement-fields-not-found": "No placeholder in the syntax <em>@replace[&quot;name&quot;]</em> were found in the template.",
     "replacement-targetfile": "Target file",
     "replacements": "Replacements in template files",
-    "replacements-info": "List of detected templates with its placeholders.",
     "repositoryinfos": "Sourcecode Repository",
     "repository-access-browser": "Browser access to sources",
     "repository-auth": "Authentication/ filename of ssh private key",
diff --git a/hooks/templates/inc_projects_config.php.erb b/hooks/templates/inc_projects_config.php.erb
index 507a21350006779e1636d753f37d239d6ac3d91d..a91d697f841da2bd8827a5a945b71c9abed34dcd 100644
--- a/hooks/templates/inc_projects_config.php.erb
+++ b/hooks/templates/inc_projects_config.php.erb
@@ -74,6 +74,13 @@ $aConfig = array(
             'debugLevel'   => 0,
         )
     ),
+    'foreman' => array(
+        'api'=>'<%= @replace["foreman-url"] %>', // with ending "/"
+        'user'=>'<%= @replace["foreman-user"] %>',
+        'password'=>'<%= @replace["foreman-password"] %>',
+        'ignore-ssl-error'=><%= @replace["ignore-ssl-error"] %>,
+        // 'varname-replace'=>'ci-replacement',
+    ),
     // where to store project data
     'projects' => array(
         'json' => array(
@@ -83,6 +90,8 @@ $aConfig = array(
             'active'       => false,
         ),
     ),
+    // notifications to messengers ...
+    'messenger'=>array(<%= @replace["messenger"] %>),    
 );
 
 // ----------------------------------------------------------------------
diff --git a/public_html/deployment/classes/config-replacement.class.php b/public_html/deployment/classes/config-replacement.class.php
index 5415757c16d5b8a3c6ab164bdba47f0087177d62..bab9519431cd67f9044b0c0aaad900aa4ab3c183 100644
--- a/public_html/deployment/classes/config-replacement.class.php
+++ b/public_html/deployment/classes/config-replacement.class.php
@@ -18,6 +18,8 @@ class configreplacement {
      * @var type 
      */
     protected $_oProject = false;
+    protected $_sPhase = false;
+    protected $_aForemanReplacements = false;
 
     
     /**
@@ -35,18 +37,17 @@ class configreplacement {
 
     /**
      * get an array with a flat list of all templatefiles of a build
-     * @param string $sPhase  name of phase
      * @return boolean|array
      */
-    public function getTemplatefiles($sPhase=false){
-        $aReturn = array();
-        if (!$sPhase){
-            $sPhase=$this->_oProject->getNextPhase(false);
+    public function getTemplatefiles(){
+        if (!$this->_sPhase){
+            return false;
         }
+        $aReturn = array();
 
-        $aBuildfiles=$this->_oProject->getBuildfilesByPlace($sPhase, 'onhold');
+        $aBuildfiles=$this->_oProject->getBuildfilesByPlace($this->_sPhase, 'onhold');
         if (!$aBuildfiles){
-            $aBuildfiles=$this->_oProject->getBuildfilesByPlace($sPhase, 'ready2install');
+            $aBuildfiles=$this->_oProject->getBuildfilesByPlace($this->_sPhase, 'ready2install');
         }
         
         if (!$aBuildfiles || !array_key_exists('types', $aBuildfiles) || !array_key_exists('templates', $aBuildfiles['types'])){
@@ -60,11 +61,13 @@ class configreplacement {
 
     /**
      * get an array with all template files (basename) and its replacement fields
-     * @param string $sPhase  name of phase
      * @return array
      */
-    public function getReplacements($sPhase=false){
-        $aFiles=$this->getTemplatefiles($sPhase);
+    public function getReplacements(){
+        if (!$this->_sPhase){
+            return false;
+        }
+        $aFiles=$this->getTemplatefiles($this->_sPhase);
         if (!$aFiles){
             return false;
         }
@@ -80,11 +83,256 @@ class configreplacement {
         return $aReturn;
     }
     
+    /**
+     * get effective hostgroup id of the current phase
+     * @return integer
+     */
+    public function getForemanHostgroup(){
+        $aPrjConfig=$this->_oProject->getConfig();
+        $iForemanHostgroupDefault = (int) $aPrjConfig['deploy']['foreman']['hostgroup'];
+        $iForemanHostgroup = (int) $aPrjConfig['phases'][$this->_sPhase]['foreman-hostgroup'];
+        return ($iForemanHostgroup===OPTION_DEFAULT) ? $iForemanHostgroupDefault : $iForemanHostgroup;
+    }
+    
+    /**
+     * get replacement definitions from foreman
+     * @global type $aConfig
+     * @return boolean
+     */
+    protected function _getForemanReplacement(){
+        global $aConfig;
+        if (!$this->_sPhase){
+            return false;
+        }
+        
+        // abort if no foreman connection was configured
+        if (!array_key_exists('foreman', $aConfig)) {
+            return false;
+        }
+
+        // return already cached result
+        if (array_key_exists($this->_sPhase, $this->_aForemanReplacements)){
+            return $this->_aForemanReplacements[$this->_sPhase];
+        }
+        
+        // rebuilt 
+        $this->_aForemanReplacements[$this->_sPhase]=false;
+        $iEffectiveHostgroup=$this->getForemanHostgroup();
+
+        // abort if no hostgroup was set
+        if($iEffectiveHostgroup<=0){
+            return false;
+        }
+
+        require_once 'foremanapi.class.php';
+        $oForeman=new ForemanApi($aConfig['foreman']);
+       
+        // get a host of this phase
+        $aHosts=$oForeman->read(array(
+            'request' => array(
+                array('hosts' ),
+            ),
+            'filter' => array(
+                'hostgroup_id' => $iEffectiveHostgroup,
+            ),
+            'response' => array('name', 'id'),
+        ));
+
+        $sHost='';
+        $aHostsOfPhase=array();
+        
+        // HACK: phases are part of the hostname .. but not "live" ... and special handling for demo
+        $aPrjConfig=$this->_oProject->getConfig();
+        $bIsDemo=(array_key_exists('fileprefix', $aPrjConfig)
+                && !strpos($aPrjConfig['fileprefix'], 'demo')===false);
+        $sPhase=$bIsDemo ? 'demo' : $this->_sPhase;
+        foreach($aHosts as $aName){
+            $sName=$aName['name'];
+            if (($sPhase==='live' &&
+                (
+                    strpos($sName, 'preview')===false
+                    && strpos($sName, 'stage')===false
+                    && strpos($sName, 'demo')===false
+                )
+            )
+               || (strpos($sName, $sPhase))
+            ){
+                $sHost=$sHost ? $sHost : $sName;
+                $aHostsOfPhase[]=$sName;
+            }
+        }
+        
+        // get created yaml of this host
+        $sUrl=$aConfig['foreman']['api']."hosts/$sHost/externalNodes?name=$sHost";
+        $aData=$oForeman->makeRequest(array(
+            'url'=>$sUrl,
+            'method'=>'GET',
+        ));
+        
+        // HACK: minify YAML of the host ... because it is too large for SPYC parser
+        $sPart="---\n";
+        $bCopy=false;
+        foreach(explode("\n", $aData['body']) as $sLine){
+            if($bCopy){
+                if (strpos($sLine, '    ')===false){
+                    $bCopy=false;
+                } else {
+                    // remove leading spaces and html entities...
+                    $sNewLine=  html_entity_decode(preg_replace('/^\ \ \ \ /', '', $sLine, 1));
+                    $sNewLine=str_replace('&#39;{', "'{", $sNewLine);
+                    $sNewLine=str_replace('}&#39;', "}'", $sNewLine);
+                    
+                    // fix json errors
+                    $sNewLine=str_replace(', }', " }", $sNewLine);
+                    $sNewLine=str_replace(',}', "}", $sNewLine);
+                    $sPart.=$sNewLine."\n";
+                }
+            }
+            if($sLine==='  iml-deployment-config:'){
+                $bCopy=true;
+            }
+            // echo 'DEBUG: '.($bCopy ? 'COPY':'SKIP').$sLine.'<br>';
+        }
+
+        require_once __DIR__.'./../../vendor/spyc/spyc.php';
+        $aYaml=spyc_load($sPart);
+
+        $aReturn=array();
+        foreach ($aYaml as $aProject){
+            foreach ($aProject as $sFile=>$aParams){
+                $aReturn[$sFile]=array();
+                if (array_key_exists('target', $aParams)){
+                    $aReturn[$sFile]['target']=$aParams['target'];
+                }
+                if (array_key_exists('replace', $aParams)){
+                    $aReplace=json_decode($aParams['replace'], 1);
+                    $aReturn[$sFile]['replace_source']=$aReplace;
+                    foreach ($aReplace as $sVarname=>$value){
+                        if (is_array($value) && array_key_exists('_'.$this->_sPhase.'_', $value)){
+                            $value=$value['_'.$this->_sPhase.'_'];
+                        }
+                        $aReturn[$sFile]['replace'][$sVarname]=$value;
+                    }
+                }
+            }
+        }
+
+        $this->_aForemanReplacements[$this->_sPhase]=array(
+            'rules'=>$aReturn,
+            'host'=>$sHost,
+            'yaml'=>$sPart,
+            'hostgroup'=>$iEffectiveHostgroup,
+            'hostsall'=>$aHosts,
+            'hostsphase'=>$aHostsOfPhase,
+        );
+        return $this->_aForemanReplacements[$this->_sPhase];
+    }
+
+    /**
+     * get foreman base url ... if foreman was activated in the setup
+     * 
+     * @global array  $aConfig  ci config
+     * @return string
+     */
+    private function _getForemanBaseUrl(){
+        global $aConfig;
+        if (!array_key_exists('foreman', $aConfig) 
+                || !array_key_exists('api', $aConfig['foreman']) 
+                || !$aConfig['foreman']['api']
+        ){
+            return false;
+        }
+        return $aConfig['foreman']['api'];
+    }
+    
+    /**
+     * get html code for links to edit each host of the current phase in foreman
+     * 
+     * @return boolean
+     */
+    public function getForemanlink2Host(){
+        $sForemanurl=$this->_getForemanBaseUrl();
+        if (!$sForemanurl){
+            return false;
+        }
+        $aTmp=$this->_getForemanReplacement();
+        if (!array_key_exists('hostsphase', $aTmp)){
+            return false;
+        }
+        require_once 'htmlguielements.class.php';
+        $oHtml=new htmlguielements();
+        $sReturn='';
+        foreach ($aTmp['hostsphase'] as $sHost){
+            $sReturn.=$oHtml->getLinkButton(array(
+                'href'=>$sForemanurl.'hosts/'.$aTmp['host'],
+                'target'=>'_foreman',
+                'title'=>t('edit'),
+                'icon'=>'host',
+                'label'=>t('host').' '.$aTmp['host'],
+            )).' ';
+        }
+        return $sReturn;
+    }
+
+    /**
+     * get html code for a link to edit hostgroup in foreman
+     * 
+     * @return boolean
+     */
+    public function getForemanlink2Hostgroup(){
+        $iEffectiveHostgroup=$this->getForemanHostgroup();
+        if($iEffectiveHostgroup<=0){
+            return false;
+        }
+        $sForemanurl=$this->_getForemanBaseUrl();
+        if (!$sForemanurl){
+            return false;
+        }
+        require_once 'htmlguielements.class.php';
+        $oHtml=new htmlguielements();
+        return $oHtml->getLinkButton(array(
+            'href'=>$sForemanurl.'hostgroups/'.$iEffectiveHostgroup.'/edit',
+            'target'=>'_foreman',
+            'title'=>t('edit'),
+            'icon'=>'hostgroup',
+            'label'=>sprintf(t('foreman-hostgroup-id'), $iEffectiveHostgroup),
+        ));
+        
+    }
+    
+    /**
+     * get replacements in foreman 
+     * @return type
+     */
+    public function getForemanReplacements(){
+        return $this->_getForemanReplacement();
+    }
+    
     /**
      * switch to a project
      * @param type $sProject
      */
-    public function setProject($sProject){
+    public function setProject($sProject, $sPhase=false){
         $this->_oProject = new project($sProject);
+        $this->_aForemanReplacements=false;
+        $this->setPhase($sPhase);
+        return true;
+    }
+    
+    /**
+     * set a phase of a project
+     * @param string  $sPhase  name of valid phase
+     * @return boolean
+     */
+    public function setPhase($sPhase=false){
+        $this->_sPhase=false;
+        if (!$sPhase){
+            $sPhase=$this->_oProject->getNextPhase(false);
+        }
+        if (!$sPhase || !$this->_oProject->isActivePhase($sPhase)) {
+            return false;
+        }
+        $this->_sPhase=$sPhase;
+        return true;
     }
 }
diff --git a/public_html/deployment/classes/foremanapi.class.php b/public_html/deployment/classes/foremanapi.class.php
new file mode 100644
index 0000000000000000000000000000000000000000..31fd9ddc8204005a40258e695b49ba405409dd24
--- /dev/null
+++ b/public_html/deployment/classes/foremanapi.class.php
@@ -0,0 +1,516 @@
+<?php
+/**
+ * ForemanApi
+ * 
+ * foreman access to API
+ * 
+ * @example
+ * in project class
+ * $oForeman=new ForemanApi($this->_aConfig['foreman']);
+ * 
+ * // enable debugging
+ * $oForeman->setDebug(1);
+ * 
+ * // self check
+ * $oForeman->selfcheck(); die(__FUNCTION__);
+ *
+ * // read operating systems and get id and title only
+ * $aForemanHostgroups=$oForeman->read(array(
+ *    'request'=>array(
+ *        array('operatingsystems'),
+ *    ),
+ *    'response'=>array(
+ *        'id','title'
+ *   ),
+ * ));
+ * 
+ * // read details for operating systems #4
+ * $aForemanHostgroups=$oForeman->read(array(
+ *    'request'=>array(
+ *        array('operatingsystems', 4),
+ *    ),
+ * ));
+ *
+ * 
+ * $aOptions ... can contain optional subkeys
+ * - request
+ *      [] list of array(keyword [,id])
+ * - filter (array)
+ *      - search (string)
+ *      - page (string)
+ *      - per_page (string)
+ * - response (array)
+ *      - list of keys, i.e. array('id', 'title')
+
+ * @author hahn
+ */
+class ForemanApi {
+
+    protected $_aCfg=array();
+    protected $_bDebug = false;
+
+    protected $_aAllowedUrls=array(
+        'api'=>array(
+            ''=>array(),
+            'architectures'=>array(),
+            'audits'=>array('methods'=>array('GET')),
+            'auth_source_ldaps'=>array(),
+            'bookmarks'=>array(),
+            'common_parameters'=>array(),
+            'compliance'=>array(),
+            'compute_attributes'=>array(),
+            'compute_profiles'=>array(),
+            'compute_resources'=>array(),
+            'config_groups'=>array(),
+            'config_reports'=>array(),
+            'config_templates'=>array(),
+            'dashboard'=>array('methods'=>array('GET')),
+            'domains'=>array(),
+            'environments'=>array(),
+            'fact_values'=>array(),
+            'filters'=>array(),
+            'hosts'=>array(),
+            'hostgroups'=>array(),
+            'job_invocations'=>array(),
+            'job_templates'=>array(),
+            'locations'=>array(),
+            'mail_notifications'=>array(),
+            'media'=>array(),
+            'models'=>array(),
+            'operatingsystems'=>array('methods'=>array('GET')),
+            'orchestration'=>array(),
+            'organizations'=>array(),
+            'permissions'=>array(),
+            'plugins'=>array(),
+            'provisioning_templates'=>array(),
+            'ptables'=>array(),
+            'puppetclasses'=>array(),
+            'realms'=>array(),
+            'remote_execution_features'=>array(),
+            'reports'=>array(),
+            'roles'=>array(),
+            'settings'=>array(),
+            'smart_class_parameters'=>array(),
+            'smart_proxies'=>array(),
+            'smart_variables'=>array(),
+            'statistics'=>array('methods'=>array('GET')),
+            'status'=>array('methods'=>array('GET')),
+            'subnets'=>array(),
+            'template_combinations'=>array(),
+            'template_kinds'=>array('methods'=>array('GET')),
+            'templates'=>array(),
+            'usergroups'=>array(),
+            'users'=>array(),
+            // ...
+        ),
+        'api/v2'=>array(
+            'discovered_hosts'=>array(),
+            'discovery_rules'=>array(),
+        ),
+        'foreman_tasks/api'=>array(
+            'recurring_logics'=>array(),
+            'tasks'=>array(),
+        ),
+    );
+    
+    
+    protected $_aRequest=array();
+    
+    
+    // ----------------------------------------------------------------------
+    // constructor
+    // ----------------------------------------------------------------------
+    
+    
+    public function __construct($aCfg) {
+        if(!is_array($aCfg) || !count($aCfg) || !array_key_exists('api', $aCfg)){
+            die("ERROR: class ".__CLASS__." must be initialized with an array containing api config for foreman.");
+            return false;
+        }
+        $this->_aCfg=$aCfg;
+        
+        return true;
+    }
+    
+    // ----------------------------------------------------------------------
+    // private functions
+    // ----------------------------------------------------------------------
+    /**
+     * add a log messsage
+     * @global object $oLog
+     * @param  string $sMessage  messeage text
+     * @param  string $sLevel    warnlevel of the given message
+     * @return bool
+     */
+    protected function log($sMessage, $sLevel = "info") {
+        global $oCLog;
+        return $oCLog->add(basename(__FILE__) . " class " . __CLASS__ . " - " . $sMessage, $sLevel);
+    }
+    
+    /**
+     * search url prefix in $this->_aAllowedUrls by given key
+     * @param type $sFunction
+     * @return type
+     */
+    protected function _guessPrefixUrl($sFunction=false){
+        $sReturn='';
+        /*
+        if (!$sFunction){
+            $sFunction=$this->_aRequest['request'][0][0];
+        }
+         * 
+         */
+        foreach($this->_aAllowedUrls as $sPrefix=>$aUrls){
+            foreach(array_keys($aUrls) as $sKeyword){
+                if ($sFunction==$sKeyword){
+                    $sReturn=$sPrefix;
+                    break;
+                }
+            }
+        }
+        return $sReturn;
+    }
+
+    /**
+     * generate an url for foreman API request based on option keys
+     * @return string
+     */
+    protected function _generateUrl(){
+        if(!array_key_exists('request', $this->_aRequest)){
+            die('ERROR: missing key [request]');
+        }
+        $sReturn=$this->_aCfg['api'];
+        
+        $sPrefix=$this->_guessPrefixUrl();
+        $sReturn.=$sPrefix.'/';
+        
+        foreach($this->_aRequest['request'] as $aReqItem){
+            if (!array_key_exists($aReqItem[0], $this->_aAllowedUrls[$sPrefix])){
+                echo 'WARNING: wrong item: [' . $aReqItem[0]."]<br>\n";
+            }
+            $sReturn.=$aReqItem[0] ? $aReqItem[0].'/' : '';
+            if(count($aReqItem)>1){
+                $sReturn.=(int)$aReqItem[1].'/';
+            }
+        }
+        return $sReturn;
+    }
+    
+    /**
+     * add parameter for search and paging in an foreman API URL
+     * 
+     * @return string
+     */
+    protected function _generateParams(){
+        if (!array_key_exists('filter', $this->_aRequest)){
+            return '';
+        }
+        $sReturn='?';
+        
+        foreach ($this->_aRequest['filter'] as $sKey=>$value){
+            $sReturn.='&'.$sKey.'='.urlencode($value);
+        }
+        return $sReturn;
+    }
+
+    /**
+     * make an http get request and return the response body
+     * it is called by _makeRequest
+     * $aRequest contains subkeys
+     * - url
+     * - method; one of GET|POST|PUT|DELETE
+     * - postdata; for POST only
+     * 
+     * @param array   $aRequest   arrayurl for Foreman API
+     * @return string
+     */
+    protected function _httpCall($aRequest=false, $iTimeout = 15) {
+        if ($aRequest){
+            $this->_aRequest=$aRequest;
+        }
+        $this->log(__FUNCTION__ . " start <pre>".print_r($this->_aRequest,1)."</pre>");
+        if (!function_exists("curl_init")) {
+            die("ERROR: PHP CURL module is not installed.");
+        }
+        
+        $sApiUser=array_key_exists('user', $this->_aCfg) ? $this->_aCfg['user'] : false;
+        $sApiPassword=array_key_exists('password', $this->_aCfg) ? $this->_aCfg['password'] : false;
+
+        $sFullUrl=$sApiUrl.$this->_aRequest['url'];
+        $this->log(__FUNCTION__ . " ".$this->_aRequest['method']." " . $this->_aRequest['url']);
+        $ch = curl_init($this->_aRequest['url']);
+
+        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $this->_aRequest['method']);
+        if ($this->_aRequest['method']==='POST'){
+            curl_setopt($ch, CURLOPT_POSTFIELDS, $this->_aRequest['postdata']);
+        }
+        curl_setopt($ch, CURLOPT_HEADER, 1);
+        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+        
+        if (array_key_exists('ignore-ssl-error', $this->_aCfg) && $this->_aCfg['ignore-ssl-error']){
+            $this->log(__FUNCTION__ . " WARNING: SSL errors will be ignored by config.", 'warning');
+            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
+            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
+        }
+        curl_setopt($ch, CURLOPT_TIMEOUT, $iTimeout);
+        curl_setopt($ch, CURLOPT_USERAGENT, 'IML Deployment GUI :: ' . __CLASS__);
+        if ($sApiUser){
+            curl_setopt($ch, CURLOPT_USERPWD, $sApiUser.":".$sApiPassword);
+        }
+
+        $res = curl_exec($ch);
+        $aReturn=array('info'=>curl_getinfo($ch), 'error'=>curl_error($ch));
+        curl_close($ch);
+        $this->log(__FUNCTION__ . " status ".$aReturn['info']['http_code'].' '.$this->_aRequest['method']." $sFullUrl");
+
+        $sHeader=substr($res, 0, $aReturn['info']['header_size']);
+        $aReturn['header']=explode("\n", $sHeader);
+        $aReturn['body']=str_replace($sHeader, "", $res);
+                
+        return $aReturn;
+    }
+
+    /**
+     * write debug infos if enabled
+     * @param string $sMessage
+     * @return boolean
+     */
+    protected function _writeDebug($sMessage){
+        if ($this->_bDebug){
+            echo "DEBUG :: ".__CLASS__." :: $sMessage<br>\n";
+        }
+        return true;
+    }
+
+    // ----------------------------------------------------------------------
+    // public functions :: low level
+    // ----------------------------------------------------------------------
+    
+    /**
+     * make an http(s) request to foreman and scan result for http code and
+     * content in response json; method returns an array with subkeys
+     * - info: curl info array
+     * - error: curl error message
+     * - header: http response headers
+     * - body: http response body
+     * - _json: parsed json data from response body
+     * - _OK: flag if result is OK and complete
+     * - _status: info
+     * 
+     *      * $aRequest contains subkeys
+     * - function --> to extract method and generate url
+     * - method; one of GET|POST|PUT|DELETE
+     * - postdata; for POST only
+
+     * @param array   $aRequest   arrayurl for Foreman API
+     * @return array
+     */
+    public function makeRequest($aRequest=false) {
+        if ($aRequest){
+            $this->_aRequest=$aRequest;
+        }
+        $sStatus='unknown';
+        $bOk=false;
+        
+        
+        // prevent missing data because of paging
+        if ($this->_aRequest['method']==='GET' && !array_key_exists('per_page', $this->_aRequest['filter'])){
+            $this->_aRequest['filter']['per_page']=1000;
+        }
+        // TODO check postdata
+        if ($this->_aRequest['method']==='POST' && (!array_key_exists('postdata',$this->_aRequest) || !count($this->_aRequest['postdata']))){
+            die("ERROR in ".__CLASS__."::".__FUNCTION__.": missing data to make a POST request");
+        }
+        if (!array_key_exists('url', $this->_aRequest)){
+            $this->_aRequest['url']=$this->_generateUrl().$this->_generateParams();
+        }
+
+        // ----- request
+        $this->_writeDebug(__FUNCTION__ . ' start request <pre>'.print_r($this->_aRequest,1).'</pre>');
+        $aReturn=$this->_httpCall();
+        
+        // ----- check result
+        // check status
+        $iStatuscode=$aReturn['info']['http_code'];
+        if ($iStatuscode===0){
+            $sStatus='wrong host';
+        }
+        if ($iStatuscode>=200 && $iStatuscode<400){
+            $sStatus='OK';
+            $bOk=true;
+        }
+        if ($iStatuscode>=400 && $iStatuscode<500){
+            $sStatus='error';
+        }
+        if ($iStatuscode===404){
+            $sStatus='wrong url';
+        }
+        
+        // check result json
+        if($bOk){
+            $aJson=json_decode($aReturn['body'], 1);
+            if (is_array($aJson)){
+                if (array_key_exists('total', $aJson) && $aJson['total'] > $aJson['per_page']){
+                    $bOk=false;
+                    $sStatus='Http OK, but incomplete results (paging)';
+                }
+                $aReturn['_json']=$aJson;
+            } else {
+                $bOk=false;
+                $sStatus='Http OK, but wrong response';
+            }
+        }
+        $aReturn['_OK']=$bOk;
+        $aReturn['_status']=$sStatus;
+        $this->_writeDebug(__FUNCTION__ . ' result of request <pre>'.print_r($aReturn,1).'</pre>');
+
+        return $aReturn;
+    }
+
+    /**
+     * filter output for the response based on values $this->_aRequest['response']
+     * @param array  $aData  response of $this->makeRequest();
+     * @return array
+     */
+    protected function _filterOutput($aData){
+        if(!array_key_exists('response', $this->_aRequest)){
+            return $aData;
+        }
+        $bIsList=array_key_exists('results', $aData['_json']);
+        $aTmp=$bIsList ? $aData['_json']['results'] : array($aData['_json']);
+        if(!count($aTmp)){
+            return array();
+        }
+        $aReturn=array();
+        foreach($aTmp as $aItem){
+            $aReturnitem=array();
+            foreach($this->_aRequest['response'] as $sKey){
+                if (array_key_exists($sKey, $aItem)){
+                    $aReturnitem[$sKey]=$aItem[$sKey];
+                }
+            }
+            $aReturn[] = $aReturnitem;
+        }
+        return ($bIsList==1)
+                ? $aReturn 
+                : (count($aReturn) ? $aReturn[0] : array());
+    }
+
+
+    // ----------------------------------------------------------------------
+    // public foreman functions
+    // ----------------------------------------------------------------------
+
+    /**
+     * enable/ disable debugging
+     * @param boolean  $bNewDebugFlag  new value; true|false
+     * @return boolean
+     */
+    public function setDebug($bNewDebugFlag){
+        return $this->_bDebug=$bNewDebugFlag;
+    }
+
+    /**
+     * check for missing config entries
+     * @return type
+     */
+    public function selfcheck() {
+        $sOut='';
+        $sWarning='';
+        $sOut.="<h1>selfcheck</h1>";
+        $aApi=$this->read(array('request'=>array(array(''))));
+        if($aApi['_OK']){
+            foreach($aApi['_json']['links'] as $sKey=>$aCalls){
+                $sOut.="<h2>$sKey</h2><ul>";
+                foreach ($aCalls as $sLabel=>$sUrl){
+                    $sOut.="<li>$sLabel .. $sUrl ";
+                    $aTmp=preg_split('#\/#', $sUrl);
+                    $sDir2=count($aTmp)>2 ? $aTmp[2] : '??';
+                    $sDir3=count($aTmp)>3 ? $aTmp[3] : '??';
+                    $sOut.="..... " 
+                        . ($this->_guessPrefixUrl($sDir2).$this->_guessPrefixUrl($sDir3)
+                            ?'<span style="background:#cfc">OK</span>'
+                            :'<span style="background:#fcc">miss</span>' 
+                        ) . ' ' . $sDir2.', '.$sDir3 . "</li>\n";
+                    if (!($this->_guessPrefixUrl($sDir2).$this->_guessPrefixUrl($sDir3))){
+                        $sWarning.="<li>$sKey - $sLabel - $sUrl</li>";
+                    }
+                }
+                $sOut.="</ul>";
+            }
+        } else {
+            $sOut.='ERROR: unable to connect to foreman or missing permissions.<br>';
+        }
+        if ($sWarning){
+            echo 'WARNINGS:<ol>'.$sWarning.'</ol>';
+        }
+        echo $sOut;
+        return true;
+    }
+    
+    // ----------------------------------------------------------------------
+    // public foreman API CRUD functions
+    // ----------------------------------------------------------------------
+    
+    /**
+     * TODO: create
+     * @param array $aOptions
+     */
+    public function create($aOptions){
+        /*
+        $this->_aRequest=$aOptions;
+        $this->_aRequest['method']='POST';
+        return $this->makeRequest();
+         */
+    }
+    /**
+     * GETTER
+     * $aOptions ... can contain optional subkeys
+     * - request
+     *      [] list of array(keyword [,id])
+     * - filter (array)
+     *      - search (string)
+     *      - page (string)
+     *      - per_page (string)
+     *      - any attribute in the return resultset
+     * - response (array)
+     *      - list of keys, i.e. array('id', 'title')
+     * 
+     * @param array  $aOptions  
+     * @return array
+     */
+    public function read($aOptions){
+        $this->_aRequest=$aOptions;
+        $this->_aRequest['method']='GET';
+        $aData=$this->makeRequest();
+        if (!$aData['_OK']){
+            return false;
+        }
+        return $this->_filterOutput($aData);
+    }
+    
+    /**
+     * TODO
+     * @param type $aOptions
+     */
+    public function update($aOptions){
+        /*
+        $this->_aRequest=$aOptions;
+        $this->_aRequest['method']='PUT';
+        return $this->makeRequest();
+         */
+    }
+    
+    /**
+     * TODO
+     * @param type $aOptions
+     */
+    public function delete($aOptions){
+        /*
+        $this->_aRequest=$aOptions;
+        $this->_aRequest['method']='DELETE';
+        return $this->makeRequest();
+         */
+    }
+    
+}
diff --git a/public_html/deployment/classes/formgen.class.php b/public_html/deployment/classes/formgen.class.php
index 61d841a64b645e9d77f595538fb87d11951f5ac4..282ae6d5de3656f2632b0f85600b633386b10f5b 100644
--- a/public_html/deployment/classes/formgen.class.php
+++ b/public_html/deployment/classes/formgen.class.php
@@ -215,7 +215,8 @@ class formgen {
             case "select":
                 // HINWEIS optgroups werden nicht unterstuezt - nur einfache Listen
                 $this->_checkReqiredKeys($elementData, array("name"));
-                $sFormElement.='<select id="' . $sId . '" class="form-control" ';
+                $sDivClass=(array_key_exists("inline", $elementData) && $elementData["inline"])?"form-group":"col-sm-10";
+                $sFormElement.='<div class="'.$sDivClass.'"><select id="' . $sId . '" class="form-control" ';
                 $sFormElement.=$this->_addHtmlAtrributes(explode(",", "$sDefaultAttributes,name,onchange"), $elementData);
                 $sFormElement.=">\n";
                 foreach ($elementData["options"] as $idOption => $aOptionData) {
@@ -225,11 +226,11 @@ class formgen {
                     $sFormElement.=$this->_addHtmlAtrributes(explode(",", "$sDefaultAttributes,selected"), $aOptionData);
                     $sFormElement.='>' . $aOptionData["label"] . '</option>' . "\n";
                 }
-                $sFormElement.="</select>\n";
+                $sFormElement.="</select></div>\n";
 
                 if ($sLabelText) {
                     // $sLabelElement.='<span class="help-block">' . $sLabelText . '</span>' . "\n";
-                    $sLabelClass=(array_key_exists("inline", $elementData) && $elementData["inline"])?"":"control-label";
+                    $sLabelClass=(array_key_exists("inline", $elementData) && $elementData["inline"])?"":"col-sm-2";
                     $sLabelElement = $this->_addLabel($sLabelText, $sId, $sLabelClass);
                 }
 
diff --git a/public_html/deployment/classes/htmlguielements.class.php b/public_html/deployment/classes/htmlguielements.class.php
index 8c9e7afe99eee9f33b78b2b3a41207d762c47acf..3264208cb40bede5e2322743a5bff86d4249da0c 100644
--- a/public_html/deployment/classes/htmlguielements.class.php
+++ b/public_html/deployment/classes/htmlguielements.class.php
@@ -43,22 +43,61 @@ class htmlguielements{
             'ok'=>array('class'=>'btn-primary', 'icon'=>'fa-check'),
             
             // deploy actions and buttons
-            'accept'=>array('class'=>'', 'icon'=>'glyphicon-forward'),
-            'build'=>array('class'=>'', 'icon'=>'glyphicon-equalizer'),
-            'cleanup'=>array('class'=>'', 'icon'=>'glyphicon-chevron-right'),
+            'accept'=>array('class'=>''),
+            'build'=>array('class'=>''),
+            'cleanup'=>array('class'=>''),
             'deploy'=>array('class'=>'', 'icon'=>'glyphicon-forward'),
             'new'=>array('class'=>'', 'icon'=>'glyphicon-star-empty'),
-            'overview'=>array('class'=>'', 'icon'=>'glyphicon-book'),
+            'overview'=>array('class'=>''),
             'phase'=>array('class'=>'', 'icon'=>'glyphicon-chevron-right'),
             'rollback'=>array('class'=>'', 'icon'=>'glyphicon-forward'),
-            'setup'=>array('class'=>'', 'icon'=>'glyphicon-cog'),
+            'setup'=>array('class'=>''),
             
         ),
         'icons'=>array(
+
+            'menu'=>'fa-chevron-right',
+            'overview'=>'fa-list',
+            'project'=>'fa-book',
+            'project-home'=>'fa-home',
+            'projects'=>'fa-folder-o',
+            'actions'=>'fa-check',
+            
+            'actionlog'=>'fa-list-ul',
+            'accept'=>'glyphicon-forward',
+            'build'=>'glyphicon-equalizer',
+            'cleanup'=>'fa-trash',
+            'checklang'=>'fa-check',
+            'delete'=>'fa-close',
+            'deploy'=>'glyphicon-forward',
+            'filter'=>'glyphicon-filter',
+            'new'=>'glyphicon-star-empty',
+            'phase'=>'glyphicon-chevron-right',
+            'rollback'=>'glyphicon-forward',
+            'setup'=>'fa-cog',
+            'login'=>'fa-lock',
+            'user'=>'fa-user',
+            
+            'workflow'=>'fa-angle-double-right',
+            'repository'=>'fa-database',
+            'phase'=>'fa-flag',
+            'package'=>'fa-cubes',
+            'version'=>'fa-tag',
+            'list'=>'fa-list',
+            'raw-data'=>'fa-file-o',
+
+            'back'=>'fa-chevron-left',
+            
             'branch'=>'glyphicon-bookmark',
             'calendar'=>'glyphicon-calendar',
             'comment'=>'glyphicon-comment',
             'revision'=>'glyphicon-tag',
+            
+            'host'=>'fa-hdd-o',
+            'hostgroup'=>'fa-sitemap',
+            'templatefile'=>'fa-file-code-o',
+            'targetfile'=>'fa-file-o',
+            'replace'=>'fa-random',            
         ),
     );
     
@@ -94,6 +133,20 @@ class htmlguielements{
         return ($sValue ? ' '.$sAttribute.'="'.$sValue.'"' : '' );
     }
     
+    /**
+     * get html attributes as string from all keys of given hash
+     * 
+     * @param array $aItem
+     * @return string
+     */
+    public function addAllAttributes($aItem){
+        $sReturn='';
+        foreach (array_keys($aItem) as $sKey){
+            $sReturn.=$this->addAttributeFromKey($sKey, $aItem);
+        }
+        return $sReturn;
+    }
+    
     // ----------------------------------------------------------------------
     // low level
     // ----------------------------------------------------------------------
@@ -113,7 +166,7 @@ class htmlguielements{
                 : ( strpos($sLabel, 'fa-')===0 ? 'fa' : '')
                 );
         if(!$sPrefix){
-            return '';
+            return $this->getIconByType($sLabel);
         }
         return '<i'.$this->addAttribute('class', ($sPrefix ? $sPrefix . ' ' : '').$sLabel).'></i> ';
     }
@@ -149,9 +202,7 @@ class htmlguielements{
         }
         
         $sReturn='<a'.$sHref;
-        foreach (array_keys($aItem) as $sKey){
-            $sReturn.=$this->addAttributeFromKey($sKey, $aItem);
-        }
+        $sReturn.=$this->addAllAttributes($aItem);
         $sReturn.='>'
                 .$sLabel
                 .'</a>';
@@ -159,7 +210,9 @@ class htmlguielements{
     }
     
     /**
-     * add default css classes and colors based on $aItem['type']
+     * add default css classes and colors based on $aItem['type'] and the
+     * local default settings in $this->aCfg
+     * 
      * @param array  $aItem
      * @return array 
      */
@@ -168,7 +221,14 @@ class htmlguielements{
         if (array_key_exists($aItem['type'], $this->aCfg['buttons'])){
             $sClass=$this->aCfg['buttons'][$aItem['type']]['class'];
             $aReturn['class'].=$sClass ? ' '.$sClass : '';
-            $aReturn['icon']=$aReturn['icon'] ? $aReturn['icon'] : $this->aCfg['buttons'][$aItem['type']]['icon'];
+            
+            // icon priority:
+            // given in param --> icon in button config --> icon in icon config
+            $aReturn['icon']=$aReturn['icon'] ? $aReturn['icon'] : 
+                ( $this->aCfg['buttons'][$aItem['type']]['icon'] 
+                    ? $this->aCfg['buttons'][$aItem['type']]['icon'] 
+                    : ( array_key_exists($aItem['type'], $this->aCfg['icons']) ? $this->aCfg['icons'][$aItem['type']] : '')
+                );
         }
         return $aReturn;
     }
@@ -269,5 +329,35 @@ class htmlguielements{
                 . '<div class="tab-content">'.$sContent.'</div>'
                 . '</div>';
     }
+
+    /**
+     * get html code for a table
+     * 
+     * @param array $aTabledata  array with subkeys "header" and "body"
+     * @return string
+     */
+    public function getTable($aTabledata) {
+        $sTHead='';
+        $sTBody='';
+        if (array_key_exists('body', $aTabledata)){
+            foreach ($aTabledata['body'] as $aRow){
+                $sTBody.='<tr>';
+                foreach ($aRow as $sItem){
+                    $sTBody.='<td>'.$sItem.'</td>';
+                }
+                $sTBody.='</tr>';
+            }
+        }
+        if (array_key_exists('header', $aTabledata)){
+            foreach ($aTabledata['header'] as $sItem){
+                $sTHead.='<th>'.$sItem.'</th>';
+            }
+        }
+        return '<table class="table" style="width: auto;">'
+            .($sTHead ? '<thead>'.$sTHead.'</thead>' : '')
+            .($sTBody ? '<tbody>'.$sTBody.'</tbody>' : '')
+            .'</table>'
+            ;
+    }
         
 }
diff --git a/public_html/deployment/classes/messenger.class.php b/public_html/deployment/classes/messenger.class.php
new file mode 100644
index 0000000000000000000000000000000000000000..91eda6c5775410c95b63272ddf72ea36033a82d1
--- /dev/null
+++ b/public_html/deployment/classes/messenger.class.php
@@ -0,0 +1,87 @@
+<?php
+
+/**
+ * send messenger notifications
+ *
+ * @author hahn
+ */
+class messenger {
+
+    /**
+     * config array for messengers
+     * @var type 
+     */
+    protected $_aCfg = array();
+    
+    /**
+     * content of messagetext to send
+     * @var string
+     */
+    protected $_sMessage = '';
+
+    /**
+     * 
+     * @example
+     * $oMessenger = new messenger(array(
+     *   'slack'=>array(
+     *     'incomingurl'=>[WebHook url],
+     *     'user'=>[visible username in slack],
+     *     'icon'=>[Slack Icon], // hm, does not seem to work
+     *   ),
+     *   'email'=>array(
+     *     'from'=>[senders e-mail]
+     *     'to'=>[email-address(es)] // multiple emails must be delimited with ";"
+     *   )
+     * ));
+     * @param array $aCfg  config array for notification targets
+     * @return boolean
+     */
+    public function __construct($aCfg) {
+        $this->_aCfg = $aCfg;
+        return true;
+    }
+
+    /**
+     * send an email if _aCfg['email'] exists
+     */
+    private function _sendEmail(){
+        if (array_key_exists('email', $this->_aCfg) && array_key_exists('to', $this->_aCfg['email'])
+        ) {
+            preg_match('/^(.*)\n/', $this->_sMessage, $aTmp);
+            $sSubject = $aTmp[0];
+            return mail($this->_aCfg['email']['to'], $sSubject, $this->_sMessage, "From: " . $this->_aCfg['email']['from'] . "\r\n" .
+                "Reply-To: " . $this->_aCfg['email']['from'] . "\r\n"
+            );
+        }
+        return false;
+    }
+    
+    /**
+     * send a message to slack if _aCfg['slack'] exists
+     */
+    private function _sendToSlack(){
+        if (array_key_exists('slack', $this->_aCfg)) {
+            require_once('./../vendor/shooker/shooker.php');
+            $shkr = new Shooker();
+            $shkr->setupIncoming($this->_aCfg['slack']['incomingurl']);
+            $sUser=(array_key_exists('user', $this->_aCfg['slack'])? $this->_aCfg['slack']['user']: false);
+            $sIcon=(array_key_exists('icon', $this->_aCfg['slack'])? $this->_aCfg['slack']['icon']: false);
+            return $shkr->sendMessage($this->_sMessage, $sUser, $sIcon);
+        }
+        return false;
+    }
+
+
+    /**
+     * send a message to all targets
+     * @param string $sMessage
+     */
+    public function sendMessage($sMessage) {
+        $this->_sMessage=$sMessage;
+        // echo '<pre>'.print_r($this->_aCfg, 1).'</pre>'.$sMessage.'<br>';
+        $this->_sendEmail();
+        $this->_sendToSlack();
+        
+    }
+
+}
diff --git a/public_html/deployment/classes/project.class.php b/public_html/deployment/classes/project.class.php
index 8699f44a5b54e89ec526a570b1b1efd2ac46e0ac..55bfe498a69ef615bb3b8165dfb5e78022fabf82 100644
--- a/public_html/deployment/classes/project.class.php
+++ b/public_html/deployment/classes/project.class.php
@@ -1,7 +1,11 @@
 <?php
 
+define("OPTION_DEFAULT", -999);
+define("OPTION_NONE", -1);
+
 require_once 'base.class.php';
 require_once 'htmlguielements.class.php';
+require_once 'messenger.class.php';
 
 /* ######################################################################
 
@@ -82,6 +86,12 @@ class project extends base {
      */
     private $_oVcs = false;
     private $_sBranchname = false;
+    
+    /**
+     * send messages
+     * @var messengerobject
+     */
+    protected $oMessenger = false;
 
     // ----------------------------------------------------------------------
     // constructor
@@ -92,7 +102,7 @@ class project extends base {
      * @param string $sId  id of the project
      */
     public function __construct($sId = false) {
-        $this->oUser=new user();
+        $this->oUser = new user();
         $this->_readConfig();
         if ($sId) {
             $this->setProjectById($sId);
@@ -114,6 +124,53 @@ class project extends base {
         return $oCLog->add(basename(__FILE__) . " class " . __CLASS__ . " - " . $sMessage, $sLevel);
     }
 
+    /**
+     * send info messages to project specific targets (Slack, E-Mail)
+     * @param string $sMessage
+     * @return boolean
+     */
+    private function _sendMessage($sMessage){
+        $aConfig=array();
+        
+        if (array_key_exists('messenger', $this->_aPrjConfig)
+           && array_key_exists('slack', $this->_aPrjConfig['messenger'])
+        ){
+            $sSlack=$this->_aPrjConfig['messenger']['slack'];
+            $aConfig['slack']=array('incomingurl'=>$sSlack);
+            foreach(array('user', 'icon') as $sKey){
+                if (array_key_exists($sKey, $this->_aConfig['messenger']['slack']['presets'][$sSlack])){
+                    $aConfig['slack'][$sKey]=$this->_aConfig['messenger']['slack']['presets'][$sSlack][$sKey];
+                }
+            }
+        }
+        
+        if (array_key_exists('messenger', $this->_aPrjConfig)
+           && array_key_exists('email', $this->_aPrjConfig['messenger'])
+           && $this->_aPrjConfig['messenger']['email']
+        ){
+            $aConfig['email']=$this->_aConfig['messenger']['email'];
+            $aConfig['email']['to']=$this->_aPrjConfig['messenger']['email'];
+        }
+        if(!count($aConfig)){
+            return false;
+        }
+        
+        // init on first usage
+        if (!$this->oMessenger){
+            $this->oMessenger=new messenger($aConfig);
+        }
+
+        // add some metadata to the message body
+        $sText=$this->getLabel().': '.html_entity_decode($sMessage)."\n" 
+                . t('page-login-username'). ": ".$this->oUser->getUsername()."\n"
+                ;
+        if (isset($_SERVER) && is_array($_SERVER)) {
+            if(array_key_exists('HTTP_ORIGIN', $_SERVER)){
+                $sText.= t('project-home').": <".$_SERVER['HTTP_ORIGIN'].'/deployment/'.$this->getId()."/>\n";
+            }
+        }
+        return $this->oMessenger->sendMessage($sText);
+    }
     /**
      * read default config file
      * @return boolean
@@ -363,7 +420,7 @@ class project extends base {
         $sBase = $this->_getFileBase($sPhase, $sPlace);
         return $sBase ? $sBase . '/' . $this->_aPrjConfig["fileprefix"] . '.tgz' : false;
     }
-    
+
     /**
      * list of files of a given phase and place
      * @param string $sPhase  one of preview|stage|live ...
@@ -371,56 +428,56 @@ class project extends base {
      * @return array
      */
     public function _getBuildfilesByDir($sBase) {
-        $aReturn=array();
-        if(!$sBase || !is_dir($sBase)){
+        $aReturn = array();
+        if (!$sBase || !is_dir($sBase)) {
             return false;
         }
-        $iTotalSize=0;
-        $aReturn=array(
-            'dir'=>$sBase,
-            'filecount'=>false,
-            'totalsize'=>false,
-            'totalsize-hr'=>false,
+        $iTotalSize = 0;
+        $aReturn = array(
+            'dir' => $sBase,
+            'filecount' => false,
+            'totalsize' => false,
+            'totalsize-hr' => false,
         );
-        
-        foreach (glob($sBase . '/*') as $sFile){
-            $sFileBase=basename($sFile);
+
+        foreach (glob($sBase . '/*') as $sFile) {
+            $sFileBase = basename($sFile);
             $sExt = pathinfo($sFile, PATHINFO_EXTENSION);
-            $aStat=stat($sFile);
-            switch($sExt){
+            $aStat = stat($sFile);
+            switch ($sExt) {
                 case 'erb':
-                    $sType='templates';
-                    $sIcon='fa fa-file-code-o';
+                    $sType = 'templates';
+                    $sIcon = 'fa fa-file-code-o';
                     break;
                 case 'tgz':
-                    $sType='package';
-                    $sIcon='fa fa-file-archive-o';
+                    $sType = 'package';
+                    $sIcon = 'fa fa-file-archive-o';
                     break;
                 case 'json':
-                    $sType='metadata';
-                    $sIcon='fa fa-file-text-o';
+                    $sType = 'metadata';
+                    $sIcon = 'fa fa-file-text-o';
                     break;
                 default:
-                    $sType='any';
-                    $sIcon='fa fa-file-o';
+                    $sType = 'any';
+                    $sIcon = 'fa fa-file-o';
                     break;
             }
             $iTotalSize+=$aStat['size'];
-            $aReturn['files'][$sFileBase]=array(
-                'type'=>$sType,
-                'icon'=>$sIcon ? '<i class="'.$sIcon.'"></i> ' : '',
-                'extension'=>$sExt,
-                'size'=>$aStat['size'],
+            $aReturn['files'][$sFileBase] = array(
+                'type' => $sType,
+                'icon' => $sIcon ? '<i class="' . $sIcon . '"></i> ' : '',
+                'extension' => $sExt,
+                'size' => $aStat['size'],
             );
-            $aReturn['types'][$sType][]=$sFileBase;
+            $aReturn['types'][$sType][] = $sFileBase;
         }
-        $aReturn['totalsize']=$iTotalSize;
-        $aReturn['totalsize-hr']=(round($iTotalSize/1024/102.4)/10).' MB';
-        $aReturn['filecount']=count($aReturn['files']);
-        
+        $aReturn['totalsize'] = $iTotalSize;
+        $aReturn['totalsize-hr'] = (round($iTotalSize / 1024 / 102.4) / 10) . ' MB';
+        $aReturn['filecount'] = count($aReturn['files']);
+
         return $aReturn;
     }
-    
+
     /**
      * list of files of a given phase and place
      * @param string $sPhase  one of preview|stage|live ...
@@ -431,16 +488,15 @@ class project extends base {
         $sBase = $this->_getFileBase($sPhase, $sPlace);
         return $this->_getBuildfilesByDir($sBase);
     }
+
     /**
      * list of files of a given version number
      * @param string $sVersion  name of version 
      * @return array
      */
     public function getBuildfilesByVersion($sVersion) {
-        return $this->_getBuildfilesByDir($this->_getProjectArchiveDir().'/'.$sVersion);
+        return $this->_getBuildfilesByDir($this->_getProjectArchiveDir() . '/' . $sVersion);
     }
-    
-
 
     /**
      * get full path of a packed project archive
@@ -624,7 +680,7 @@ class project extends base {
      * @return array
      */
     public function cleanupArchive($bDeleteAll = false) {
-        if (!$this->oUser->hasPermission("project-action-cleanup")){
+        if (!$this->oUser->hasPermission("project-action-cleanup")) {
             return $this->oUser->showDenied();
         }
         $aDelete = array();
@@ -632,10 +688,10 @@ class project extends base {
 
         $sDir = $this->_getProjectArchiveDir();
         $this->getVersions();
-        if (!$this->_aVersions){
+        if (!$this->_aVersions) {
             return $aDelete;
         }
-        
+
         // find unused versions
         foreach ($this->_aVersions as $sVersion => $aUsage) {
             if (!$aUsage || count($aUsage) == 0) {
@@ -648,15 +704,15 @@ class project extends base {
         while (count($aUnused) && count($aUnused) > $iKeep) {
             $sVersion = array_shift($aUnused);
             $sDir2 = $sDir . '/' . $sVersion;
-            if (is_dir($sDir2)){
+            if (is_dir($sDir2)) {
                 if ($this->_rmdir($sDir2)) {
                     $aDelete[] = $sDir2;
-                    echo t('ok').': '.$sDir2;
+                    echo t('ok') . ': ' . $sDir2;
                 } else {
                     echo sprintf(t("class-project-warning-cannot-delete-archive-dir"), $sDir2);
                 }
             } else {
-                echo t('skip').': '.$sDir2;
+                echo t('skip') . ': ' . $sDir2;
             }
             echo '<br>';
         }
@@ -676,7 +732,7 @@ class project extends base {
      */
     public function cleanupBuilds() {
         $this->log(__FUNCTION__ . " start");
-        if (!$this->oUser->hasPermission("project-action-cleanup")){
+        if (!$this->oUser->hasPermission("project-action-cleanup")) {
             return $this->oUser->showDenied();
         }
         $sDir = $this->_getBuildDir();
@@ -709,7 +765,7 @@ class project extends base {
      */
     public function cleanupVcsCache($iAge = 0) {
         $this->log(__FUNCTION__ . " start");
-        if (!$this->oUser->hasPermission("project-action-cleanup")){
+        if (!$this->oUser->hasPermission("project-action-cleanup")) {
             return $this->oUser->showDenied();
         }
         $this->_initVcs();
@@ -747,6 +803,13 @@ class project extends base {
         return $this->_aPrjConfig["description"];
     }
 
+    /**
+     * get the id of the current project
+     * @return string
+     */
+    public function getId(){
+        return $this->_aConfig["id"];
+    }
     /**
      * get deploy and queue infos for all phases
      * @return type
@@ -828,39 +891,39 @@ class project extends base {
                 $aTmp[$sKey] = array();
 
                 // use version cache
-                require_once(__DIR__. '/../../valuestore/classes/valuestore.class.php');
+                require_once(__DIR__ . '/../../valuestore/classes/valuestore.class.php');
                 $oVersion = new valuestore();
                 $oVersion->setProject("", $this->_aPrjConfig["fileprefix"], $sPhase, $sKey);
-                $aVersions=$oVersion->getVersion();
+                $aVersions = $oVersion->getVersion();
                 // echo "Place: <pre>" . print_r($oVersion->whereiam(), 1) . "</pre>";
                 // echo "Versionen: <pre>" . print_r($aVersions, 1) . "</pre>";
-                foreach ($aVersions as $sHostname=>$aHostdata){
-                    $aTmp[$sKey]=array();
-                    $aTmp[$sKey]=$aHostdata['_data'];
+                foreach ($aVersions as $sHostname => $aHostdata) {
+                    $aTmp[$sKey] = array();
+                    $aTmp[$sKey] = $aHostdata['_data'];
                     $aTmp[$sKey]["infofile"] = '[versioncache]';
-                    
-                    $aTmp[$sKey]['_hosts']=array();
-                    $aTmp[$sKey]['_hosts'][$aHostdata['host']]=$aHostdata;
-                    
+
+                    $aTmp[$sKey]['_hosts'] = array();
+                    $aTmp[$sKey]['_hosts'][$aHostdata['host']] = $aHostdata;
+
                     // first host only
                     continue;
                 }
                 $aTmp[$sKey]["ok"] = 1;
                 $aTmp[$sKey]["infofile"] = '[versioncache]';
                 /*
-                $sJsonData = $this->_httpGet($sJsonfile);
-                if ($sJsonData) {
-                    $aJson = json_decode($sJsonData, true);
-                    if (is_array($aJson) && array_key_exists("version", $aJson)) {
-                        $aTmp[$sKey] = $aJson;
-                        $aTmp[$sKey]["infofile"] = $sJsonfile;
-                        $aTmp[$sKey]["ok"] = 1;
-                    } else {
-                        $aTmp[$sKey]["error"] = sprintf(t("class-project-error-metafile-has-no-version"), $sJsonfile, print_r($aJson, true));
-                    }
-                } else {
-                    $aTmp[$sKey]["error"] = sprintf(t("class-project-error-metafile-wrong-format"), $sJsonfile);
-                }
+                  $sJsonData = $this->_httpGet($sJsonfile);
+                  if ($sJsonData) {
+                  $aJson = json_decode($sJsonData, true);
+                  if (is_array($aJson) && array_key_exists("version", $aJson)) {
+                  $aTmp[$sKey] = $aJson;
+                  $aTmp[$sKey]["infofile"] = $sJsonfile;
+                  $aTmp[$sKey]["ok"] = 1;
+                  } else {
+                  $aTmp[$sKey]["error"] = sprintf(t("class-project-error-metafile-has-no-version"), $sJsonfile, print_r($aJson, true));
+                  }
+                  } else {
+                  $aTmp[$sKey]["error"] = sprintf(t("class-project-error-metafile-wrong-format"), $sJsonfile);
+                  }
                  * 
                  */
             } else {
@@ -959,9 +1022,8 @@ class project extends base {
      * @param type $sPhase  current phase
      */
     public function canAcceptPhase($sPhase = false) {
-        if (!$this->oUser->hasPermission("project-action-accept")
-            && !$this->oUser->hasPermission("project-action-accept-$sPhase")
-        ){
+        if (!$this->oUser->hasPermission("project-action-accept") && !$this->oUser->hasPermission("project-action-accept-$sPhase")
+        ) {
             // echo $this->oUser->showDenied();
             return false;
         }
@@ -997,14 +1059,7 @@ class project extends base {
         // array key "ok" must be in the ready2install and deployed info
         // and a version must be installed
         if (
-                array_key_exists($sPhase, $this->_aData["phases"]) 
-                && array_key_exists("onhold", $this->_aData["phases"][$sPhase]) 
-                && array_key_exists("ready2install", $this->_aData["phases"][$sPhase]) 
-                && array_key_exists("deployed", $this->_aData["phases"][$sPhase]) 
-                && array_key_exists("ok", $this->_aData["phases"][$sPhase]["onhold"]) 
-                && array_key_exists("ok", $this->_aData["phases"][$sPhase]["ready2install"]) 
-                && array_key_exists("ok", $this->_aData["phases"][$sPhase]["deployed"])
-                && array_key_exists("version", $this->_aData["phases"][$sPhase]["deployed"])
+                array_key_exists($sPhase, $this->_aData["phases"]) && array_key_exists("onhold", $this->_aData["phases"][$sPhase]) && array_key_exists("ready2install", $this->_aData["phases"][$sPhase]) && array_key_exists("deployed", $this->_aData["phases"][$sPhase]) && array_key_exists("ok", $this->_aData["phases"][$sPhase]["onhold"]) && array_key_exists("ok", $this->_aData["phases"][$sPhase]["ready2install"]) && array_key_exists("ok", $this->_aData["phases"][$sPhase]["deployed"]) && array_key_exists("version", $this->_aData["phases"][$sPhase]["deployed"])
         ) {
             return true;
         }
@@ -1224,76 +1279,72 @@ class project extends base {
         $this->_sProcessTempOut = $sNewTempfile;
         return $this->_sProcessTempOut;
     }
-    
-        /**
-         * get projects from ldap; it returns ldap search items with cn as 
-         * array key.
-         * 
-         * @return array
-         */
-        private function _ldapProjectSearch($sSearchFilter) {
-            $aReturn = array();
-            require_once("ldap.class.php");
-            $oLdapIML = new imlldap($this->_aConfig['projects']['ldap']);
-            // $oLdapIML->debugOn();
-            $aResultsIml = $oLdapIML->searchDn(
-                $this->_aConfig['projects']['ldap']['DnProjects'],
-                $sSearchFilter, 
-                array("*")
-            );
-            if (!$aResultsIml['count']) {
-                return false;
-            }
-            $oLdapIML->close();
 
-            /*
-            unset($aResultsIml['count']);
-            foreach ($aResultsIml as $aItem) {
-                $aReturn[$aItem['cn'][0]] = array(
-                    'dn' => $aItem['dn'],
-                    'cn' => $aItem['cn'][0],
-                    '_description' => $aItem['description'][0],
-                    'title' => $sTitle,
-                    'description' => $sDescription,
-                );
-            }
-            $oLdapIML->close();
-            ksort($aReturn);
-            return $aReturn;
-             * 
-             */
-            return $aResultsIml;
+    /**
+     * get projects from ldap; it returns ldap search items with cn as 
+     * array key.
+     * 
+     * @return array
+     */
+    private function _ldapProjectSearch($sSearchFilter) {
+        $aReturn = array();
+        require_once("ldap.class.php");
+        $oLdapIML = new imlldap($this->_aConfig['projects']['ldap']);
+        // $oLdapIML->debugOn();
+        $aResultsIml = $oLdapIML->searchDn(
+                $this->_aConfig['projects']['ldap']['DnProjects'], $sSearchFilter, array("*")
+        );
+        if (!$aResultsIml['count']) {
+            return false;
         }
+        $oLdapIML->close();
+
+        /*
+          unset($aResultsIml['count']);
+          foreach ($aResultsIml as $aItem) {
+          $aReturn[$aItem['cn'][0]] = array(
+          'dn' => $aItem['dn'],
+          'cn' => $aItem['cn'][0],
+          '_description' => $aItem['description'][0],
+          'title' => $sTitle,
+          'description' => $sDescription,
+          );
+          }
+          $oLdapIML->close();
+          ksort($aReturn);
+          return $aReturn;
+         * 
+         */
+        return $aResultsIml;
+    }
 
     /**
      * load config of a project
      * @return boolean
      */
     public function setProjectById($sId) {
-        if ($sId !== preg_replace('/[^a-z0-9\-\_]/i', '', $sId)){
+        if ($sId !== preg_replace('/[^a-z0-9\-\_]/i', '', $sId)) {
             echo "ERROR: invalid syntax in project ID: $sId<br>";
             return false;
         }
         $this->_aPrjConfig = array();
         $this->_aConfig["id"] = $sId;
 
-        
-        if ($this->_aConfig['projects']['json']['active']){
+
+        if ($this->_aConfig['projects']['json']['active']) {
             $this->_aPrjConfig = json_decode(file_get_contents($this->_getConfigFile($sId)), true);
         }
-        if ($this->_aConfig['projects']['ldap']['active']){
+        if ($this->_aConfig['projects']['ldap']['active']) {
             // TODO: read project after saving it - @see $this->saveConfig()
-            $sQuery='(&(objectclass=hieraSource)(documentIdentifier='.$sId.'))';
-            $aResult=$this->_ldapProjectSearch($sQuery);
+            $sQuery = '(&(objectclass=hieraSource)(documentIdentifier=' . $sId . '))';
+            $aResult = $this->_ldapProjectSearch($sQuery);
             // echo '<pre>$aResult = ' . print_r($aResult, 1) . '</pre>';
-            if (is_array($aResult) 
-                    && $aResult[0]
-                    && array_key_exists('hieradata',$aResult[0])
-            ){
-                foreach ($aResult[0]['hieradata'] as $sLine){
+            if (is_array($aResult) && $aResult[0] && array_key_exists('hieradata', $aResult[0])
+            ) {
+                foreach ($aResult[0]['hieradata'] as $sLine) {
                     // echo $sLine.'<br>';
-                    if(preg_match('/^cfg=/', $sLine)){
-                        
+                    if (preg_match('/^cfg=/', $sLine)) {
+
                         // echo $sLine.'<br>';
                         $this->_aPrjConfig = json_decode(preg_replace('/^cfg=/', '', $sLine), 1);
                     }
@@ -1373,7 +1424,6 @@ class project extends base {
         return file_exists($this->_sProcessTempOut);
     }
 
-
     /**
      * get the name of the current branch (or default branch)
      * @return string
@@ -1399,12 +1449,12 @@ class project extends base {
      */
     public function build($sTmpFile = false) {
         $this->log(__FUNCTION__ . " start");
-        if (!$this->oUser->hasPermission("project-action-build")){
+        if (!$this->oUser->hasPermission("project-action-build")) {
             return $this->oUser->showDenied();
         }
         global $aParams;
         $sReturn = false;
-        $oHtml=new htmlguielements();
+        $oHtml = new htmlguielements();
 
         $aActionList = array(
             'iActive' => 0,
@@ -1502,7 +1552,7 @@ class project extends base {
             $sReturn.=$this->_execAndSend('chmod 755 ' . $filename);
             $sReturn.=$this->_execAndSend('ls -l ' . $filename);
         }
-        
+
         $sReturn.=$oHtml->getBox("success", t('class-project-info-build-checkout-ok'));
         $aActionList['iActive'] ++;
         $this->_TempFill($sReturn, $aActionList);
@@ -1730,7 +1780,7 @@ class project extends base {
         $this->_logaction(t('starting') . " queue($sPhase, $sVersion)", __FUNCTION__);
         $sReturn = "<h2> " . t("queue") . " " . $this->getLabel() . " :: $sPhase</h2>";
         $this->_TempFill($sReturn, $aActionList);
-        $oHtml=new htmlguielements();
+        $oHtml = new htmlguielements();
 
         if (!$this->isActivePhase($sPhase)) {
             $sError = sprintf(t("class-project-warning-phase-not-active"), $sPhase);
@@ -1803,11 +1853,10 @@ class project extends base {
      * @return boolean|string
      */
     public function deploy($sPhase, $bIgnoreDeploytimes = false) {
-        $oHtml=new htmlguielements();
+        $oHtml = new htmlguielements();
         $this->log(__FUNCTION__ . " start");
-        if (!$this->oUser->hasPermission("project-action-deploy")
-            && !$this->oUser->hasPermission("project-action-deploy-$sPhase")
-        ){
+        if (!$this->oUser->hasPermission("project-action-deploy") && !$this->oUser->hasPermission("project-action-deploy-$sPhase")
+        ) {
             return $this->oUser->showDenied();
         }
         $aActionList = array(
@@ -1860,6 +1909,8 @@ class project extends base {
                     // $this->_logaction($sError, __FUNCTION__);
                     $sReturn.=$oHtml->getBox("info", $sError);
                     $this->_TempDelete();
+                    // removed: cronjob sends this message too
+                    // $this->_sendMessage($sError."\n".t('phase').': '.$sPhase);
                     return $sReturn;
                 } else {
                     $sReturn.=t("class-project-info-deploy-time-not-reached-and-ignored") . "<br>";
@@ -1875,6 +1926,7 @@ class project extends base {
             $this->_logaction($sError, __FUNCTION__, "error");
             $sReturn.=$oHtml->getBox("info", $sError);
             $this->_TempDelete();
+            $this->_sendMessage($sError."\n".t('phase').': '.$sPhase);
             return $sReturn;
         }
         $this->_TempFill($sReturn);
@@ -1900,6 +1952,7 @@ class project extends base {
             $sError = t("class-project-error-command-failed");
             $this->_logaction($sError, __FUNCTION__, "error");
             $sReturn.=$oHtml->getBox("error", $sError . $sReturn);
+            $this->_sendMessage($sError."\n".t('phase').': '.$sPhase);
             return $sReturn;
         }
 
@@ -1948,39 +2001,40 @@ class project extends base {
         // run action to install
         // --------------------------------------------------
         $sDeploymethod = array_key_exists("deploymethod", $this->_aPrjConfig["phases"][$sPhase]) ? $this->_aPrjConfig["phases"][$sPhase]["deploymethod"] : "none";
-        $sTargethosts=array_key_exists("hosts", $this->_aPrjConfig["phases"][$sPhase]) ? $this->_aPrjConfig["phases"][$sPhase]["hosts"] : '';
-        
-        $sReturn.='<h3>' . t("class-project-info-deploy-start-by-method") . ' :: '.$sDeploymethod.'</h3>'
-                .'<p>'
-                .t("deploymethod-$sDeploymethod").'<br>'
-                .t("phase-targethosts").': '.($sTargethosts ? $sTargethosts : t("none"))
-                .'</p>'
-                ;
-        if ($sDeploymethod==="none" || !$sTargethosts){
+        $sTargethosts = array_key_exists("hosts", $this->_aPrjConfig["phases"][$sPhase]) ? $this->_aPrjConfig["phases"][$sPhase]["hosts"] : '';
+
+        $sReturn.='<h3>' . t("class-project-info-deploy-start-by-method") . ' :: ' . $sDeploymethod . '</h3>'
+                . '<p>'
+                . t("deploymethod-$sDeploymethod") . '<br>'
+                . t("phase-targethosts") . ': ' . ($sTargethosts ? $sTargethosts : t("none"))
+                . '</p>'
+        ;
+        if ($sDeploymethod === "none" || !$sTargethosts) {
             $sReturn.=t("class-project-info-deploy-start-by-method-skip") . "<br>";
         } else {
-            $aTargethosts=explode(',', $sTargethosts);
-            foreach ($aTargethosts as $sTargethost){
-                $sReturn.='<h4>' . $sDeploymethod . ' - '.$sTargethost.'</h4>';
-                $sCmd='';
-                switch($sDeploymethod){
+            $aTargethosts = explode(',', $sTargethosts);
+            foreach ($aTargethosts as $sTargethost) {
+                $sReturn.='<h4>' . $sDeploymethod . ' - ' . $sTargethost . '</h4>';
+                $sCmd = '';
+                switch ($sDeploymethod) {
                     case 'puppet':
                         $sCmd = 'ssh ' . $this->_aConfig["installPackages"]["user"]
                                 . '@' . $sTargethost
                                 . ' ' . $this->_aConfig["installPackages"]["command"];
-                        break;;
+                        break;
+                        ;
                     // TODO: we don't have any proxy yet
                     case 'sshproxy__AS_EXAMPLE_ONLY':
                         $sCmd = 'ssh ' . $this->_aConfig["installPackages"]["sshproxy"]["user"]
                                 . '@' . $this->_aConfig["installPackages"]["sshproxy"]["host"]
                                 . ' ' . sprintf($this->_aConfig["installPackages"]["sshproxy"]["command"], $sTargethost);
-                        break;;
+                        break;
+                        ;
                 }
-                if ($sCmd){
+                if ($sCmd) {
                     // $sReturn.=$sCmd.'<br>';
                     $sReturn.=$this->_execAndSend("$sCmd");
                 }
-
             }
         }
         $aActionList['iActive'] ++;
@@ -1988,6 +2042,8 @@ class project extends base {
 
         $sReturn.="<br>";
         $sReturn.=$oHtml->getBox("success", t("class-project-info-deploy-successful"));
+        
+        $this->_sendMessage(t("class-project-info-deploy-successful")."\n"."phase: $sPhase");
         $this->_logaction(t('finished') . " deploy($sPhase, $bIgnoreDeploytimes) " . t("class-project-info-deploy-successful"), __FUNCTION__, "success");
         $this->_TempDelete();
         return $sReturn;
@@ -2000,11 +2056,10 @@ class project extends base {
      * @return type
      */
     public function accept($sPhase) {
-        $oHtml=new htmlguielements();
+        $oHtml = new htmlguielements();
         $this->log(__FUNCTION__ . " start");
-        if (!$this->oUser->hasPermission("project-action-accept")
-            && !$this->oUser->hasPermission("project-action-accept-$sPhase")
-            ){
+        if (!$this->oUser->hasPermission("project-action-accept") && !$this->oUser->hasPermission("project-action-accept-$sPhase")
+        ) {
             return $this->oUser->showDenied();
         }
 
@@ -2040,16 +2095,16 @@ class project extends base {
      */
     public function saveConfig($aData = false) {
         $this->log(__FUNCTION__ . " start");
-        if (!$this->oUser->hasPermission("project-action-setup")){
+        if (!$this->oUser->hasPermission("project-action-setup")) {
             return $this->oUser->showDenied();
         }
         $this->_logaction(t('starting') . " saveConfig(...)", __FUNCTION__);
         if (!$aData) {
             $aData = $_POST;
         }
-        
-        foreach(array('id', 'label', 'description', 'contact', 'build', 'fileprefix', 'phases') as $sKey){
-            if (!array_key_exists($sKey, $aData)){
+
+        foreach (array('id', 'label', 'description', 'contact', 'build', 'fileprefix', 'phases') as $sKey) {
+            if (!array_key_exists($sKey, $aData)) {
                 $this->_logaction(t('abortet') . " missing key $sKey in savedata", __FUNCTION__, "error");
                 return false;
             }
@@ -2058,13 +2113,13 @@ class project extends base {
 
         // remove unwanted items
         foreach (array("setupaction", "prj", "id") as $s) {
-            if (array_key_exists($s, $aData)){
+            if (array_key_exists($s, $aData)) {
                 unset($aData[$s]);
             }
         }
 
         // save json file
-        if ($this->_aConfig['projects']['json']['active']){
+        if ($this->_aConfig['projects']['json']['active']) {
             // echo "IST <pre>" . print_r($this->_aPrjConfig, true) . "</pre>"; echo "NEU <pre>" . print_r($aData, true) . "</pre>"; die();
             // make a backup of a working config
             $sCfgFile = $this->_getConfigFile($sId);
@@ -2075,51 +2130,55 @@ class project extends base {
             $this->_aPrjConfig = json_decode(file_get_contents($this->_getConfigFile($sId)), true);
         }
         // save in ldap
-        if ($this->_aConfig['projects']['ldap']['active']){
+        if ($this->_aConfig['projects']['ldap']['active']) {
             // TODO: 
-            echo "TODO: save in LDAP<br><pre>" . print_r($aData, 1) ."</pre>";
-            
-            
-            $sDn='documentIdentifier='.$sId.','.$this->_aConfig['projects']['ldap']['DnProjects'];
-            $aItem=array(
+            echo "TODO: save in LDAP<br><pre>" . print_r($aData, 1) . "</pre>";
+
+
+            $sDn = 'documentIdentifier=' . $sId . ',' . $this->_aConfig['projects']['ldap']['DnProjects'];
+            $aItem = array(
                 'objectClass' => array(
                     'document',
                     'hieraSource',
                     'top',
                 ),
                 'hieraData' => array(
-                    'cfg='.json_encode($aData),
-                    'updated='.date("Y-m-d H:i:s") . ' by ' . $this->oUser->getUsername(),
+                    'cfg=' . json_encode($aData),
+                    'updated=' . date("Y-m-d H:i:s") . ' by ' . $this->oUser->getUsername(),
                 )
             );
-            
+
             require_once("ldap.class.php");
             $oLdapIML = new imlldap($this->_aConfig['projects']['ldap']);
             // $oLdapIML->debugOn();
-            if (!$oLdapIML->DnExists($sDn)){            
-                if ($oLdapIML->objAdd($sDn,$aItem)){
+            if (!$oLdapIML->DnExists($sDn)) {
+                if ($oLdapIML->objAdd($sDn, $aItem)) {
                     echo 'OK, created in LDAP.<br>';
-                    $bReturn=true;
+                    $bReturn = true;
                 } else {
-                    echo 'ERROR, DN '.$sDn.' was not created in LDAP :-/<br>';
-                    $bReturn=false;
+                    echo 'ERROR, DN ' . $sDn . ' was not created in LDAP :-/<br>';
+                    $bReturn = false;
                 }
             } else {
-                if ($oLdapIML->objUpdate($sDn,$aItem)){
+                if ($oLdapIML->objUpdate($sDn, $aItem)) {
                     echo 'OK, updated in LDAP.<br>';
-                    $bReturn=true;
+                    $bReturn = true;
                 } else {
-                    echo 'ERROR, DN '.$sDn.' was not updated in LDAP :-/<br>';
-                    $bReturn=false;
+                    echo 'ERROR, DN ' . $sDn . ' was not updated in LDAP :-/<br>';
+                    $bReturn = false;
                 }
             }
             $oLdapIML->close();
-            
         }
-            
+
         $this->_logaction(t('finished') . " saveConfig(...)", __FUNCTION__, "success");
         $this->setProjectById($sId);
 
+        $sMessage=($bReturn 
+                ? t("page-setup-info-settings-were-saved")
+                : t("page-setup-error-settings-were-not-saved")
+        );
+        $this->_sendMessage($sMessage);
         return $bReturn;
     }
 
@@ -2131,7 +2190,7 @@ class project extends base {
      */
     public function create($sId) {
         $this->log(__FUNCTION__ . " start");
-        if (!$this->oUser->hasPermission("project-action-create")){
+        if (!$this->oUser->hasPermission("project-action-create")) {
             return $this->oUser->showDenied();
         }
         $this->_logaction(t('starting') . " create($sId)", __FUNCTION__);
@@ -2199,7 +2258,7 @@ class project extends base {
      */
     public function delete($aOptions = array()) {
         $this->log(__FUNCTION__ . " start");
-        if (!$this->oUser->hasPermission("project-action-delete")){
+        if (!$this->oUser->hasPermission("project-action-delete")) {
             return $this->oUser->showDenied();
         }
         $sCfgfile = $this->_getConfigFile($this->_aConfig["id"]);
@@ -2247,6 +2306,7 @@ class project extends base {
                 }
             }
         }
+        $this->_sendMessage(t('finished') . " delete()");
         $this->_logaction(t('finished') . " delete()", __FUNCTION__, "success");
         return false;
     }
@@ -2303,62 +2363,66 @@ class project extends base {
         }
         return $this->_getChecksumDiv($aData["revision"]);
     }
-    
-    private function _renderHostsData($aData){
-        $sReturn='';
-        if (array_key_exists('_hosts', $aData)){
+
+    private function _renderHostsData($aData) {
+        $sReturn = '';
+        if (array_key_exists('_hosts', $aData)) {
+            $oHtml = new htmlguielements();
+            
             // $sReturn.= print_r($aData['_hosts'], 1);
             $sReturn.= '<div class="hosts">'
-                    . '<br><strong>'.t('hosts').':</strong><br>'
-                    ;
-            foreach($aData['_hosts'] as $sHostname=>$aHostinfos){
-                $oUpdateDate=date("U", strtotime($aHostinfos['time']));
-                $iAgeUpdate=round((date("U")-$oUpdateDate)/ 60);
-                $sAge=$iAgeUpdate< 60*60*13 ? $iAgeUpdate. " min" : "??";
+                    . '<br><strong>' . t('hosts') . ':</strong><br>'
+            ;
+            foreach ($aData['_hosts'] as $sHostname => $aHostinfos) {
+                $oUpdateDate = date("U", strtotime($aHostinfos['time']));
+                $iAgeUpdate = round((date("U") - $oUpdateDate) / 60);
+                $sAge = $iAgeUpdate < 60 * 60 * 13 ? $iAgeUpdate . " min" : "??";
 
                 $sReturn.= '<div class="host">'
                         . $this->_getChecksumDiv($aHostinfos['_data']['revision'])
-                        . '<i class="fa fa-cube"></i><br>'
+                        . $oHtml->getIcon('host').'<br>'
                         . $sHostname . "<br>($sAge) "
                         . '</div>'
-                        ;
+                ;
             }
             $sReturn.= '</div><div style="clear: both;"></div>';
         }
         return $sReturn;
     }
+
     /**
      * get html code for list of hosts in a phase
      * @param string $sPhase  phase of a project
      * @return string
      */
-    private function _renderHosts($sPhase){
+    private function _renderHosts($sPhase) {
         $aDataPhase = $this->getPhaseInfos($sPhase);
-        if (is_array($aDataPhase) && array_key_exists('deployed', $aDataPhase)){
+        if (is_array($aDataPhase) && array_key_exists('deployed', $aDataPhase)) {
             return $this->_renderHostsData($aDataPhase['deployed']);
         }
         return '';
     }
+
     /**
      * get html code for list of files in a phase
      * @param string $sPhase  phase of a project
      * @return string
      */
-    private function _renderFiles($sPhase){
-        $sReturn='';
-        $aFiles=$this->getBuildfilesByPlace($sPhase, 'ready2install');
-        if (!$aFiles || !$aFiles['filecount']){
+    private function _renderFiles($sPhase) {
+        $sReturn = '';
+        $aFiles = $this->getBuildfilesByPlace($sPhase, 'ready2install');
+        if (!$aFiles || !$aFiles['filecount']) {
             return '';
         }
-        $sReturn.='<strong>'.t("filelist").'</strong> ('.$aFiles['filecount'].'):<br>';
-        foreach($aFiles['files'] as $sFilename => $aData){
-            $sReturn.='<div class="file file-'.$aData['type'].' fileext-'.$aData['extension'].'" title="'.$sFilename.' ('.$aData['type'].')">'
-                    . $aData['icon'] . $sFilename 
+        $sReturn.='<strong>' . t("filelist") . '</strong> (' . $aFiles['filecount'] . '):<br>';
+        foreach ($aFiles['files'] as $sFilename => $aData) {
+            $sReturn.='<div class="file file-' . $aData['type'] . ' fileext-' . $aData['extension'] . '" title="' . $sFilename . ' (' . $aData['type'] . ')">'
+                    . $aData['icon'] . $sFilename
                     // . ' ('.$aData['type'].')'
                     . '</div>'
-                    ;
+            ;
         }
-        $sReturn.='('.$aFiles['totalsize-hr'].')';
+        $sReturn.='(' . $aFiles['totalsize-hr'] . ')';
         return $sReturn;
     }
 
@@ -2371,7 +2435,7 @@ class project extends base {
     public function renderLink($sFunction, $sPhase = false, $sVersion = false) {
         $sFirst = $this->getNextPhase();
         $sNext = $this->getNextPhase($sPhase);
-        $oHtml=new htmlguielements();
+        $oHtml = new htmlguielements();
         $aLinkdata = array(
             'default' => array('class' => ''),
             'accept' => array('class' => $sNext,
@@ -2410,19 +2474,19 @@ class project extends base {
             ),
         );
         /*
-        if (!$this->oUser->hasRole("project-action-$sFunction")){
-            // $sClass .= ' disabled';
-            // return '<span title="no permission [project-action-'.$sFunction.']">[ ]</span>';
-        } 
+          if (!$this->oUser->hasRole("project-action-$sFunction")){
+          // $sClass .= ' disabled';
+          // return '<span title="no permission [project-action-'.$sFunction.']">[ ]</span>';
+          }
          * 
-         */       
+         */
         // fuer wen ist der Link
         $sRole = '';
         $sOnMouseover = '';
         $sOnMouseout = '';
         if ($sFunction == "build") {
             $sRole = 'developer';
-            $sOnMouseover = '$(\'.' . $sNext . '.td' . $this->_aConfig["id"] . '\').addClass(\'highlight\');'; 
+            $sOnMouseover = '$(\'.' . $sNext . '.td' . $this->_aConfig["id"] . '\').addClass(\'highlight\');';
             $sOnMouseout = '$(\'.' . $sNext . '.td' . $this->_aConfig["id"] . '\').removeClass(\'highlight\');';
         }
         if ($sFunction == "accept") {
@@ -2431,8 +2495,8 @@ class project extends base {
                 $sRole = 'pl';
                 // $aLinkdata[$sFunction]['icon']='glyphicon glyphicon-star';
             }
-            $sOnMouseover = '$(\'.' . $sNext . '.td' . $this->_aConfig["id"] . '\').addClass(\'highlight\');'; 
-            $sOnMouseout ='$(\'.' . $sNext . '.td' . $this->_aConfig["id"] . '\').removeClass(\'highlight\');';
+            $sOnMouseover = '$(\'.' . $sNext . '.td' . $this->_aConfig["id"] . '\').addClass(\'highlight\');';
+            $sOnMouseout = '$(\'.' . $sNext . '.td' . $this->_aConfig["id"] . '\').removeClass(\'highlight\');';
         }
 
         // $sClass = $sPhase;
@@ -2460,19 +2524,19 @@ class project extends base {
         if ($sVersion) {
             $sLink.="$sVersion/";
         }
-        if (!$this->oUser->hasPermission("project-action-$sFunction")){
+        if (!$this->oUser->hasPermission("project-action-$sFunction")) {
             // $sClass .= ' disabled';
-            return '<span title="no permission [project-action-'.$sFunction.'] for '.$this->oUser->getUsername().'">[ <i class="' . $sIconClass . '"></i> ' . $sLabel . ' ]</span>';
-        }        
+            return '<span title="no permission [project-action-' . $sFunction . '] for ' . $this->oUser->getUsername() . '">[ <i class="' . $sIconClass . '"></i> ' . $sLabel . ' ]</span>';
+        }
 
         return $oHtml->getLinkButton(array(
-            'href'=>$sLink,
-            'title'=>$sHint,
-            'class'=>'btn btn-default ' . $sClass,
-            'type'=>$sFunction,
-            'onmouseover'=>$sOnMouseover,
-            'onmouseout'=>$sOnMouseout,
-            'label'=>$sLabel,
+                    'href' => $sLink,
+                    'title' => $sHint,
+                    'class' => 'btn btn-default ' . $sClass,
+                    'type' => $sFunction,
+                    'onmouseover' => $sOnMouseover,
+                    'onmouseout' => $sOnMouseout,
+                    'label' => $sLabel,
         ));
         // return '<a href="' . $sLink . '" ' . $sOnMouseover . ' title="' . $sHint . '" class="btn  btn-default ' . $sClass . '"><i class="' . $sIconClass . '"></i> ' . $sLabel . '</a>';
     }
@@ -2489,21 +2553,21 @@ class project extends base {
             $sRow1.='<th class="' . $sPhase . '">' . $sPhase . '</th>';
             $sRow2.='<td class="' . $sPhase . '">'
                     . t('url') . ': <a href="' . $this->_aPrjConfig["phases"][$sPhase]["url"] . '">' . $this->_aPrjConfig["phases"][$sPhase]["url"] . '</a><br>'
-                    . '<br>' . t('deploytimes') . ':<br>';            
+                    . '<br>' . t('deploytimes') . ':<br>';
             if (count($this->_getDeploytimes($sPhase))) {
                 $sRow2.=implode("<br>", $this->_getDeploytimes($sPhase));
             } else {
                 $sRow2.=t('deploytimes-immediately');
             }
             $sRow2.='<br>' . $this->renderLink("phase", $sPhase)
-                . $this->_renderHosts($sPhase)
-                .'<br>'
-                . $this->_renderFiles($sPhase)
-                . '</td>';
+                    . $this->_renderHosts($sPhase)
+                    . '<br>'
+                    . $this->_renderFiles($sPhase)
+                    . '</td>';
         }
         return '<table><thead><tr>' . $sRow1 . '</tr></thead><tbody><tr>' . $sRow2 . '</tr></tbody></table>';
     }
-    
+
     /**
      * render html for a place of a phase
      * @param string  $sPhase    phase
@@ -2531,93 +2595,92 @@ class project extends base {
         $aDataPhase = $this->getPhaseInfos($sPhase);
         $aData = $aDataPhase[$sPlace];
         // foreach($aDataPhase[$sPlace] as $aData) {
-            if (array_key_exists("ok", $aData) && array_key_exists("version", $aData)) {
-                // TODO: getChecksumDiv anhand der Repo-Versionsnummer - dann kann man beim build auch die Farbe mit dem Repo HEAD vergleichen
-                
-                // time
-                $sDateFormat="d.m.Y H:i";
-                $oPkgDate=date("U", strtotime($aData["date"]));
-                /*
-                $iAge=date("U")-$oPkgDate;
-                $sAgeClass="";
-                if ($iAge< 60*60*24*3){
-                    $sAgeClass="last1d";
-                }
-                if ($iAge< 60*60){
-                    $sAgeClass="last1h";
-                }
-                */
-                $sReturn .= '
+        if (array_key_exists("ok", $aData) && array_key_exists("version", $aData)) {
+            // TODO: getChecksumDiv anhand der Repo-Versionsnummer - dann kann man beim build auch die Farbe mit dem Repo HEAD vergleichen
+            // time
+            $sDateFormat = "d.m.Y H:i";
+            $oPkgDate = date("U", strtotime($aData["date"]));
+            /*
+              $iAge=date("U")-$oPkgDate;
+              $sAgeClass="";
+              if ($iAge< 60*60*24*3){
+              $sAgeClass="last1d";
+              }
+              if ($iAge< 60*60){
+              $sAgeClass="last1h";
+              }
+             */
+            $sReturn .= '
                     ' . $this->_renderBar($sPhase, $sPlace) . '
                     <i class="glyphicon glyphicon-calendar"></i> ' . date($sDateFormat, $oPkgDate);
-                
-                if ($bLong) {
-                    // long display of the revision
-                    // $sJsonUrl = $this->_getInfofile($sPhase, $sPlace);
-                    $sReturn.='<br>
+
+            if ($bLong) {
+                // long display of the revision
+                // $sJsonUrl = $this->_getInfofile($sPhase, $sPlace);
+                $sReturn.='<br>
                         <i class="glyphicon glyphicon-bookmark"></i> ' . t('branch') . ': ' . $aData["branch"] . '<br>
                         <i class="glyphicon glyphicon-tag"></i> ' . t('revision') . ': ' . $this->_renderRevision($aData["revision"]) . '<br>
                         <i class="glyphicon glyphicon-comment"></i> ' . t('commitmessage') . ':<br><pre>' . strip_tags($aData["message"], '<br>') . '</pre>'
-                        // . '<i class="glyphicon glyphicon-globe"></i> ' . t('url') . ': <a href="' . $sJsonUrl . '">' . $sJsonUrl . '</a><br>'
-                        ;
-                    if ($sPlace == "deployed" && array_key_exists("url", $this->_aPrjConfig["phases"][$sPhase])) {
-                        $sUrl = $this->_aPrjConfig["phases"][$sPhase]["url"];
-                        $sReturn.='<i class="glyphicon glyphicon-globe"></i> ' . t('url') . ': <a href="' . $sUrl . '">' . $sUrl . '</a><br>';
-                    }
-                } else {
-                    if ($sPlace == "deployed" && array_key_exists("url", $this->_aPrjConfig["phases"][$sPhase])) {
-                        $sMore = '<i class="glyphicon glyphicon-globe"></i> ' 
-                                . t('url') 
-                                . ': <a href="' . $this->_aPrjConfig["phases"][$sPhase]["url"] . '">' . $this->_aPrjConfig["phases"][$sPhase]["url"] . '</a><br>';
-                    }
-
-                    $sReturn.=' ' . $this->renderInfoLink(
-                                    $aData, array(
-                                'title' => $this->getLabel() . " :: $sPhase :: $sPlace",
-                                'more' => $sMore,
-                                    )
-                    );
+                // . '<i class="glyphicon glyphicon-globe"></i> ' . t('url') . ': <a href="' . $sJsonUrl . '">' . $sJsonUrl . '</a><br>'
+                ;
+                if ($sPlace == "deployed" && array_key_exists("url", $this->_aPrjConfig["phases"][$sPhase])) {
+                    $sUrl = $this->_aPrjConfig["phases"][$sPhase]["url"];
+                    $sReturn.='<i class="glyphicon glyphicon-globe"></i> ' . t('url') . ': <a href="' . $sUrl . '">' . $sUrl . '</a><br>';
+                }
+            } else {
+                if ($sPlace == "deployed" && array_key_exists("url", $this->_aPrjConfig["phases"][$sPhase])) {
+                    $sMore = '<i class="glyphicon glyphicon-globe"></i> '
+                            . t('url')
+                            . ': <a href="' . $this->_aPrjConfig["phases"][$sPhase]["url"] . '">' . $this->_aPrjConfig["phases"][$sPhase]["url"] . '</a><br>';
                 }
 
-                switch ($sPlace) {
-                    case "onhold":
-                        if (array_key_exists("phases", $this->_aConfig) && array_key_exists($sPhase, $this->_aConfig["phases"])) {
-                            // $sReturn .= print_r($this->_aConfig["phases"][$sPhase], true);
-                            if (count($this->_getDeploytimes($sPhase))) {
-                                $sReturn .= '<br><i class="glyphicon glyphicon-time"></i> ' . t('deploytimes') . ':<br>'
-                                        . implode("<br>", array_values($this->_getDeploytimes($sPhase)))
-                                        . '<br>';
-                            }
-                            if ($bActions) {
-                                $sReturn .= ' ' . $this->renderLink("deploy", $sPhase);
-                            }
+                $sReturn.=' ' . $this->renderInfoLink(
+                                $aData, array(
+                            'title' => $this->getLabel() . " :: $sPhase :: $sPlace",
+                            'more' => $sMore,
+                                )
+                );
+            }
+
+            switch ($sPlace) {
+                case "onhold":
+                    if (array_key_exists("phases", $this->_aConfig) && array_key_exists($sPhase, $this->_aConfig["phases"])) {
+                        // $sReturn .= print_r($this->_aConfig["phases"][$sPhase], true);
+                        if (count($this->_getDeploytimes($sPhase))) {
+                            $sReturn .= '<br><i class="glyphicon glyphicon-time"></i> ' . t('deploytimes') . ':<br>'
+                                    . implode("<br>", array_values($this->_getDeploytimes($sPhase)))
+                                    . '<br>';
                         }
-                        break;
+                        if ($bActions) {
+                            $sReturn .= ' ' . $this->renderLink("deploy", $sPhase);
+                        }
+                    }
+                    break;
 
-                    case "ready2install":
-                        break;
+                case "ready2install":
+                    break;
 
-                    case "deployed":
-                        if ($bActions && $this->canAcceptPhase($sPhase)) {
-                            $sReturn .= ' ' . $this->renderLink("accept", $sPhase);
-                        }
-                        break;
-                    default:
-                        break;
-                }
-                // $this->_getChecksumDiv($aData["revision"])
+                case "deployed":
+                    if ($bActions && $this->canAcceptPhase($sPhase)) {
+                        $sReturn .= ' ' . $this->renderLink("accept", $sPhase);
+                    }
+                    break;
+                default:
+                    break;
+            }
+            // $this->_getChecksumDiv($aData["revision"])
+        } else {
+            if (array_key_exists("error", $aData)) {
+                $sReturn.=''
+                        . $this->renderInfoLink(array('error' => $aData["error"]), array())
+                ;
+            } else if (array_key_exists("warning", $aData)) {
+                $sReturn.= '<div class="warning"><i class="glyphicon glyphicon-info-sign"></i> ' . t('warning') . ':<br>' . $aData["warning"] . '</div>';
             } else {
-                if (array_key_exists("error", $aData)) {
-                    $sReturn.=''
-                            .$this->renderInfoLink(array('error'=>$aData["error"]),array())
-                            ;
-                } else if (array_key_exists("warning", $aData)) {
-                    $sReturn.= '<div class="warning"><i class="glyphicon glyphicon-info-sign"></i> ' . t('warning') . ':<br>' . $aData["warning"] . '</div>';
-                } else {
-                    return false;
-                    // $sReturn.= t('empty');
-                }
-            } // if
+                return false;
+                // $sReturn.= t('empty');
+            }
+        } // if
         // } // for
         return $sReturn;
     }
@@ -2675,7 +2738,7 @@ class project extends base {
      * @return string
      */
     public function renderRepoInfo() {
-        $oHtml=new htmlguielements();
+        $oHtml = new htmlguielements();
         $sReturn = "";
         switch ($this->_aPrjConfig["build"]["type"]) {
             case "git":
@@ -2712,12 +2775,12 @@ class project extends base {
      * @param string $sRevision
      * @return string
      */
-    public function _renderRevision($sRevision){
-        $sUrl=str_replace('/tree/master','',$this->_aPrjConfig["build"]["webaccess"]).'/commit/'.$sRevision;
-        return '<a href="'.$sUrl.'">'.$sRevision.'</a>';
+    public function _renderRevision($sRevision) {
+        $sUrl = str_replace('/tree/master', '', $this->_aPrjConfig["build"]["webaccess"]) . '/commit/' . $sRevision;
+        return '<a href="' . $sUrl . '">' . $sRevision . '</a>';
         return $sUrl;
     }
-    
+
     /**
      * render html code for info link that shows popup with metadata on mouseover
      * @param array $aInfos   metainfos of the package (from json file)
@@ -2731,7 +2794,7 @@ class project extends base {
     public function renderInfoLink($aInfos, $aOptions = array()) {
         $sReturn = '';
         $bIsError = false;
-        $oHtml=new htmlguielements();
+        $oHtml = new htmlguielements();
 
         $sInfos.='';
         if (array_key_exists("title", $aOptions) && $aOptions["title"]) {
@@ -2741,10 +2804,10 @@ class project extends base {
             $sLinktitle = t('infos');
             if (array_key_exists("message", $aInfos)) {
                 $sInfos.=$this->_getChecksumDiv($aInfos["revision"])
-                        . $oHtml->getIconByType('calendar') . t('build-from')    . ' '  . date("d.m.Y H:i:s", strtotime($aInfos["date"])) . '<br>'
-                        . $oHtml->getIconByType('branch')   . t('branch')        . ': ' . $aInfos["branch"] . '<br>'
-                        . $oHtml->getIconByType('revision') . t('revision')      . ': ' . $this->_renderRevision($aInfos["revision"]) . '<br>'
-                        . $oHtml->getIconByType('comment')  . t('commitmessage') . ':<br><span class="pre">' . strip_tags($aInfos["message"], '<br>') . '</span>';
+                        . $oHtml->getIconByType('calendar') . t('build-from') . ' ' . date("d.m.Y H:i:s", strtotime($aInfos["date"])) . '<br>'
+                        . $oHtml->getIconByType('branch') . t('branch') . ': ' . $aInfos["branch"] . '<br>'
+                        . $oHtml->getIconByType('revision') . t('revision') . ': ' . $this->_renderRevision($aInfos["revision"]) . '<br>'
+                        . $oHtml->getIconByType('comment') . t('commitmessage') . ':<br><span class="pre">' . strip_tags($aInfos["message"], '<br>') . '</span>';
                 if (array_key_exists("more", $aOptions)) {
                     $sInfos.=$aOptions["more"];
                 }
@@ -2764,11 +2827,11 @@ class project extends base {
         }
 
         // render html
-        $sId='info'.md5($sInfos);
-        $sReturn = '<a href="#" class="btn '.($bIsError ? 'btn-danger': 'btn-default').'" onclick="showIdAsModalMessage(\''.$sId.'\'); return false;">'
+        $sId = 'info' . md5($sInfos);
+        $sReturn = '<a href="#" class="btn ' . ($bIsError ? 'btn-danger' : 'btn-default') . '" title="" onclick="showIdAsModalMessage(\'' . $sId . '\'); return false;">'
                 // . '<i class="fa fa-info"></i> '
                 . $sLinktitle
-                . '</a><div id="'.$sId.'" style="display: none;" ';
+                . '</a><div id="' . $sId . '" style="display: none;" ';
         if (array_key_exists("hpos", $aOptions)) {
             $sReturn.=' class="' . $aOptions["hpos"] . '"';
         }
@@ -2777,7 +2840,7 @@ class project extends base {
         if ($sTitle) {
             $sReturn.='<span class="title">' . $sTitle . '</span><br><br>';
         }
-        
+
         $sReturn.=$sInfos . '</div>';
 
         if ($bIsError) {
@@ -2792,7 +2855,7 @@ class project extends base {
      * @return string
      */
     public function renderVersionUsage() {
-        $oHtml=new htmlguielements();
+        $oHtml = new htmlguielements();
         $sReturn = false;
         $sRowHead1 = false;
         $sRowHead2 = '';
@@ -2950,17 +3013,94 @@ class project extends base {
      * @return string
      */
     public function renderProjectSetup() {
-        if (!$this->oUser->hasPermission("project-action-setup")){
+        if (!$this->oUser->hasPermission("project-action-setup")) {
             return $this->oUser->showDenied();
         }
-        $oHtml=new htmlguielements();
+        $oHtml = new htmlguielements();
         $sMessages = '';
         require_once ("formgen.class.php");
+
         
-        require_once("./classes/config-replacement.class.php");
-        $oConfig = new configreplacement();
-        $oConfig->setProject($this->_aConfig["id"]);
+        $aSelectSlack = array(
+                'type' => 'hidden',
+                'name' => 'messenger[slack]',
+                'value' => false,
+        );
+        if (
+                array_key_exists('messenger', $this->_aConfig)
+                && array_key_exists('slack', $this->_aConfig['messenger'])
+                && array_key_exists('presets', $this->_aConfig['messenger']['slack'])
+                && count(array_key_exists('presets', $this->_aConfig['messenger']['slack']['presets']))
+        ) {
+            $aSelectSlack = array(
+                'type' => 'select',
+                'name' => 'messenger[slack]',
+                'label' => t("messenger-slack"),
+                'options' => array(
+                    OPTION_NONE => array(
+                        'label' => t('none'),
+                    ),
+                    '' => array(
+                        'label' => '- - - - - - - - - - - - - - - - - - - - ',
+                    ),
+                ),
+            );
+            foreach($this->_aConfig['messenger']['slack']['presets'] as $sSlackUrl=>$aSlackCfg){
+                $bActive=$this->_aPrjConfig['messenger']['slack'] === $sSlackUrl;
+                $aSelectSlack['options'][$sSlackUrl] = array(
+                    'label' => array_key_exists('label', $aSlackCfg) ? $aSlackCfg['label'] : $sSlackUrl,
+                    'selected' => $bActive ? 'selected' : false,
+                );
+            }
+            
+        }
         
+        $aForemanHostgroups = false;
+        $iForemanHostgroupDefault = false;
+        $sForemanHostgroupDefault = false;
+        if (array_key_exists('foreman', $this->_aConfig)) {
+            // echo '<pre>' . print_r($this->_aPrjConfig, 1) . '</pre>';
+            $iForemanHostgroupDefault = (int) $this->_aPrjConfig['deploy']['foreman']['hostgroup'];
+            require_once('foremanapi.class.php');
+            $oForeman = new ForemanApi($this->_aConfig['foreman']);
+            // $oForeman->setDebug(1);
+            // $oForeman->selfcheck(); die(__FUNCTION__);
+
+            $aForemanHostgroups = $oForeman->read(array(
+                'request' => array(
+                    array('hostgroups'),
+                // array('operatingsystems',4),
+                ),
+                'response' => array(
+                    'id', 'title'
+                ),
+            ));
+            $aSelectForemanGroups = array(
+                'type' => 'select',
+                'name' => 'deploy[foreman][hostgroup]',
+                'label' => t("foreman-hostgroup"),
+                'options' => array(
+                    OPTION_NONE => array(
+                        'label' => t('none'),
+                    ),
+                    '' => array(
+                        'label' => '- - - - - - - - - - - - - - - - - - - - ',
+                    ),
+                ),
+            );
+            if (count($aForemanHostgroups)) {
+                foreach ($aForemanHostgroups as $aItem) {
+                    $bActive=$iForemanHostgroupDefault === (int) $aItem['id'];
+                    $aSelectForemanGroups['options'][$aItem['id']] = array(
+                        'label' => $aItem['title'],
+                        'selected' => $bActive ? 'selected' : false,
+                    );
+                    $sForemanHostgroupDefault = $bActive ? $aItem['title'] : $sForemanHostgroupDefault;
+                }
+            }
+        }
+
+
         $i = 0;
 
         $aPrefixItem = count($this->getVersions()) ?
@@ -3021,12 +3161,10 @@ class project extends base {
                         'type' => 'markup',
                         'value' => '<div class="tabbable">
                             <ul class="nav nav-tabs">
-                                <li class="active"><a href="#tab1" data-toggle="tab">' . t('setup-metadata') . '</a></li>
-                                <li><a href="#tab2" data-toggle="tab">' . t('build') . '</a></li>
-                                <li><a href="#tab3" data-toggle="tab">' . t('phases') . '</a></li>
-                                <!--
-                                <li><a href="#tab3" data-toggle="tab">' . t('deployment') . '</a></li>
-                                -->
+                                <li class="active"><a href="#tab1" data-toggle="tab">' . $oHtml->getIcon('list').t('setup-metadata') . '</a></li>
+                                <li><a href="#tab2" data-toggle="tab">' . $oHtml->getIcon('repository').t('repositoryinfos') . '</a></li>
+                                <li><a href="#tab3" data-toggle="tab">' . $oHtml->getIcon('phase').t('phases') . '</a></li>
+                                <li><a href="#tab4" data-toggle="tab">' . $oHtml->getIcon('raw-data').t('raw-data') . '</a></li>
                             </ul>
                             <div class="tab-content">
                             <div class="tab-pane active" id="tab1">
@@ -3063,6 +3201,22 @@ class project extends base {
                         'size' => 100,
                         'placeholder' => '',
                     ),
+                    
+                    'input' . $i++ => array(
+                        'type' => 'markup',
+                        'value' => '<p>' . t('messenger') . '</p>',
+                    ),
+                    'input' . $i++ => array(
+                        'type' => 'text',
+                        'name' => 'messenger[email]',
+                        'label' => t("messenger-email"),
+                        'value' => $this->_aPrjConfig["messenger"]["email"],
+                        'validate' => 'isastring',
+                        'size' => 100,
+                        'placeholder' => '',
+                    ),
+                    
+                    'input' . $i++ => $aSelectSlack,
                     // --------------------------------------------------
                     'input' . $i++ => array(
                         'type' => 'markup',
@@ -3130,33 +3284,73 @@ class project extends base {
                 ),
             ),
         );
+        if ($aSelectForemanGroups) {
+            $aForms["setup"]["form"]['input' . $i++] = array(
+                'type' => 'markup',
+                'value' => '<strong>'.t("defaults-all-phases").'</strong><br><br>',
+            );
+            $aForms["setup"]["form"]['input' . $i++] = $aSelectForemanGroups;
+            $aForms["setup"]["form"]['input' . $i++] = array(
+                'type' => 'markup',
+                'value' => '<br><br>',
+            );
+        }
         foreach (array_keys($this->getPhases()) as $sPhase) {
-            
+
             $bActivePhase = $this->isActivePhase($sPhase);
             $sUrl = array_key_exists("url", $this->_aPrjConfig["phases"][$sPhase]) ? $this->_aPrjConfig["phases"][$sPhase]["url"] : "";
             $sDeploymethod = array_key_exists("deploymethod", $this->_aPrjConfig["phases"][$sPhase]) ? $this->_aPrjConfig["phases"][$sPhase]["deploymethod"] : "";
             $sDeployhosts = array_key_exists("hosts", $this->_aPrjConfig["phases"][$sPhase]) ? $this->_aPrjConfig["phases"][$sPhase]["hosts"] : "";
-            
-            $sDeploytimes = array_key_exists("deploytimes", $this->_aPrjConfig["phases"][$sPhase]) ? $this->_aPrjConfig["phases"][$sPhase]["deploytimes"] : "";
-            $sDivId4PhaseSettings='divSettings'.$sPhase;
-            $sDivId4TargetHosts='divSettings'.$sPhase.'hosts';
 
+            $sDeploytimes = array_key_exists("deploytimes", $this->_aPrjConfig["phases"][$sPhase]) ? $this->_aPrjConfig["phases"][$sPhase]["deploytimes"] : "";
+            $sDivId4PhaseSettings = 'divSettings' . $sPhase;
+            $sDivId4TargetHosts = 'divSettings' . $sPhase . 'hosts';
+
+            if ($aSelectForemanGroups) {
+                $iForemanHostgroup = (int) $this->_aPrjConfig['phases'][$sPhase]['foreman-hostgroup'];
+                $aSelectForemanHostGroup = array(
+                    'type' => 'select',
+                    'name' => 'phases[' . $sPhase . '][foreman-hostgroup]',
+                    'label' => t("foreman-hostgroup"),
+                    'options' => array(
+                        OPTION_DEFAULT => array(
+                            'label' => t('default') . ' (' . $sForemanHostgroupDefault . ')',
+                            'selected' => $iForemanHostgroup === OPTION_DEFAULT ? 'selected' : false,
+                        ),
+                        OPTION_NONE => array(
+                            'label' => t('none'),
+                            'selected' => $iForemanHostgroup === OPTION_NONE ? 'selected' : false,
+                        ),
+                        '' => array(
+                            'label' => '- - - - - - - - - - - - - - - - - - - - ',
+                        ),
+                    ),
+                );
+                if (count($aForemanHostgroups)) {
+                    foreach ($aForemanHostgroups as $aItem) {
+                        $aSelectForemanHostGroup['options'][$aItem['id']] = array(
+                            'label' => $aItem['title'],
+                            'selected' => ($iForemanHostgroup === $aItem['id']) ? 'selected' : false,
+                        );
+                    }
+                }
+            }
             $aForms["setup"]["form"]['input' . $i++] = array(
                 'type' => 'markup',
                 'value' => ''
-                    // .'<pre>'.print_r($this->_aPrjConfig["phases"][$sPhase], 1).'</pre>'
-                    /*
-                    . '<a class="'.$sPhase.'">'
-                    . t("phase") . ' ' . $sPhase
-                    . '</a>'
-                     */
-                    . '<table class="table">'
-                    . '<tbody>'
-                    . '<tr><th class="' . $sPhase . '">'. t("phase") . ' ' . $sPhase.'</th></tr>'
-                    . '<tr><td class="' . ($bActivePhase ? $sPhase : '') . '">'
+                // .'<pre>'.print_r($this->_aPrjConfig["phases"][$sPhase], 1).'</pre>'
+                /*
+                  . '<a class="'.$sPhase.'">'
+                  . t("phase") . ' ' . $sPhase
+                  . '</a>'
+                 */
+                . '<table class="table">'
+                . '<tbody>'
+                . '<tr><th class="' . $sPhase . '">' . t("phase") . ' ' . $sPhase . '</th></tr>'
+                . '<tr><td class="' . ($bActivePhase ? $sPhase : '') . '">'
                 . ''
             );
-            
+
             $aForms["setup"]["form"]['input' . $i++] = array(
                 'type' => 'checkbox',
                 'name' => 'phases[' . $sPhase . '][active]',
@@ -3170,19 +3364,14 @@ class project extends base {
                     '1' => array(
                         'label' => t("yes"),
                         'checked' => $bActivePhase,
-                        'onclick' => '$(\'#'.$sDivId4PhaseSettings.'\').css(\'display\', (this.checked ? \'block\' : \'none\') )',
+                        'onclick' => '$(\'#' . $sDivId4PhaseSettings . '\').css(\'display\', (this.checked ? \'block\' : \'none\') )',
                     ),
                 ),
-                
             );
             $aForms["setup"]["form"]['input' . $i++] = array(
                 'type' => 'markup',
                 'value' => ''
-                .'<div id="'.$sDivId4PhaseSettings.'" '.($bActivePhase ? '' : ' style="display: none;"').'">'
-            );
-            $aForms["setup"]["form"]['input' . $i++] = array(
-                'type' => 'markup',
-                'value' => '<div style="clear: both"></div><div class="form-group"><h3>'.t("deploy-settings").'</h3></div>'
+                . '<div id="' . $sDivId4PhaseSettings . '" ' . ($bActivePhase ? '' : ' style="display: none;"') . '">'
             );
             $aForms["setup"]["form"]['input' . $i++] = array(
                 'type' => 'text',
@@ -3206,29 +3395,28 @@ class project extends base {
                 'options' => array(
                     'none' => array(
                         'label' => t("deploymethod-none"),
-                        'checked' => $sDeploymethod==="none",
-                        'onclick' => '$(\'#'.$sDivId4TargetHosts.'\').css(\'display\', (this.checked ? \'none\' : \'block\') )',
+                        'checked' => $sDeploymethod === "none",
+                        'onclick' => '$(\'#' . $sDivId4TargetHosts . '\').css(\'display\', (this.checked ? \'none\' : \'block\') )',
                     ),
                     'puppet' => array(
                         'label' => t("deploymethod-puppet"),
-                        'checked' => $sDeploymethod==="puppet",
-                        'onclick' => '$(\'#'.$sDivId4TargetHosts.'\').css(\'display\', (this.checked ? \'block\' : \'none\') )',
+                        'checked' => $sDeploymethod === "puppet",
+                        'onclick' => '$(\'#' . $sDivId4TargetHosts . '\').css(\'display\', (this.checked ? \'block\' : \'none\') )',
                     ),
-                    /*
-                     * see deploy method to handle an action
-                    'sshproxy' => array(
-                        'label' => t("deploymethod-sshproxy"),
-                        'checked' => $sDeploymethod==="sshproxy",
-                        'onclick' => '$(\'#'.$sDivId4TargetHosts.'\').css(\'display\', (this.checked ? \'block\' : \'none\') )',
-                    ),
-                     */
+                /*
+                 * see deploy method to handle an action
+                  'sshproxy' => array(
+                  'label' => t("deploymethod-sshproxy"),
+                  'checked' => $sDeploymethod==="sshproxy",
+                  'onclick' => '$(\'#'.$sDivId4TargetHosts.'\').css(\'display\', (this.checked ? \'block\' : \'none\') )',
+                  ),
+                 */
                 ),
-                
             );
             $aForms["setup"]["form"]['input' . $i++] = array(
                 'type' => 'markup',
                 'value' => ''
-                .'<div id="'.$sDivId4TargetHosts.'" '.($sDeploymethod!=="none" ? '' : ' style="display: none;"').'">'
+                . '<div id="' . $sDivId4TargetHosts . '" ' . ($sDeploymethod !== "none" ? '' : ' style="display: none;"') . '">'
             );
             $aForms["setup"]["form"]['input' . $i++] = array(
                 'type' => 'text',
@@ -3242,37 +3430,37 @@ class project extends base {
             );
 
             /*
-            if ($sPuppethost) {
-
-                // add ssh host key
-                $sOut0 = shell_exec(sprintf($this->_aConfig["installPackages"]["addkeycommand"], $sPuppethost, $sPuppethost));
-
-                $sCmd2 = 'ssh ' . $this->_aConfig["installPackages"]["user"]
-                        . '@' . $sPuppethost
-                        . ' ' . $this->_aConfig["installPackages"]["testcommand"];
-                $sOut = 'skip';
-                // $sOut = shell_exec($sCmd2);
-                // Check auf Versionsnummer - mehr als n Zeichen ist mutmasslich eine Fehlermeldung
-                if (strlen($sOut) > 7) {
-                    $sMessages.=$this->getBox("error", sprintf(t("class-project-error-setup-sudo-pupet-agent-failed"), $sPhase, $sCmd, $sOut));
-                    $sOut = '<span class="error" title="' . $sCmd . '">' . $sOut . '</span>';
-                } else {
-                    $sOut = '<span class="ok">' . sprintf(t("class-project-info-setup-ssh-and-puppet-ok"), $sPuppethost) . '</span>';
-                }
-                $aForms["setup"]["form"]['input' . $i++] = array(
-                    'type' => 'markup',
-                    'value' => '<div class="form-group">'
-                    . '<label class="col-sm-2"> </label><div class="col-sm-10">'
-                    . $sOut
-                    . '</div></div>',
-                );
-            }
-            */
-                        
+              if ($sPuppethost) {
+
+              // add ssh host key
+              $sOut0 = shell_exec(sprintf($this->_aConfig["installPackages"]["addkeycommand"], $sPuppethost, $sPuppethost));
+
+              $sCmd2 = 'ssh ' . $this->_aConfig["installPackages"]["user"]
+              . '@' . $sPuppethost
+              . ' ' . $this->_aConfig["installPackages"]["testcommand"];
+              $sOut = 'skip';
+              // $sOut = shell_exec($sCmd2);
+              // Check auf Versionsnummer - mehr als n Zeichen ist mutmasslich eine Fehlermeldung
+              if (strlen($sOut) > 7) {
+              $sMessages.=$this->getBox("error", sprintf(t("class-project-error-setup-sudo-pupet-agent-failed"), $sPhase, $sCmd, $sOut));
+              $sOut = '<span class="error" title="' . $sCmd . '">' . $sOut . '</span>';
+              } else {
+              $sOut = '<span class="ok">' . sprintf(t("class-project-info-setup-ssh-and-puppet-ok"), $sPuppethost) . '</span>';
+              }
+              $aForms["setup"]["form"]['input' . $i++] = array(
+              'type' => 'markup',
+              'value' => '<div class="form-group">'
+              . '<label class="col-sm-2"> </label><div class="col-sm-10">'
+              . $sOut
+              . '</div></div>',
+              );
+              }
+             */
+
             $aForms["setup"]["form"]['input' . $i++] = array(
                 'type' => 'markup',
                 'value' => ''
-                .'</div>'
+                . '</div>'
             );
             // when to deploy
             $aForms["setup"]["form"]['input' . $i++] = array(
@@ -3285,95 +3473,18 @@ class project extends base {
                 'size' => 100,
                 'placeholder' => implode(", ", $this->_aConfig["phases"][$sPhase]["deploytimes"]),
             );
-            
-            $aReplacements=$oConfig->getReplacements($sPhase);
-            $sDivIdReplacement='divreplacements-'.$sPhase;
-            $aForms["setup"]["form"]['input' . $i++] = array(
-                'type' => 'markup',
-                'value' => '<div style="clear: both; height: 2em;"></div>'
-                    . '<div class="form-group">'
-                    . ($aReplacements 
-                        ? '<a class="expandable closed" href="#" onclick="$(\'#'.$sDivIdReplacement.'\').slideToggle(); $(this).toggleClass(\'closed\'); return false;">'
-                        : '' 
-                    )
-                    . '<h3>'.t("replacements").'  ('.($aReplacements ? count($aReplacements):0).')</h3>'
-                    . ($aReplacements ? '</a>' : '')
-                    . t('replacements-info')
-                    . '</div>'
-            );
-            
-            if ($aReplacements){
-                $aForms["setup"]["form"]['input' . $i++] = array(
-                    'type' => 'markup',
-                    'value' => '<div id="'.$sDivIdReplacement.'" style="display: none;">'
-                );
-                foreach($aReplacements as $sFile=>$aFields){
-                    $tTplFile=basename($sFile);
-                    $aValues = (array_key_exists("replace", $this->_aPrjConfig["phases"][$sPhase])
-                            && array_key_exists($tTplFile, $this->_aPrjConfig["phases"][$sPhase]["replace"])
-                            )
-                            ? $this->_aPrjConfig["phases"][$sPhase]["replace"][$tTplFile] : false;
-                    $aForms["setup"]["form"]['input' . $i++] = array(
-                        'type' => 'markup',
-                        'value' => '<div class="form-group"><br><h4><i class="fa fa-file-code-o"></i> '.$tTplFile.'</h4>'
-                        // . '<textarea cols="100" rows="7" >'.file_get_contents($sFile).'</textarea>'
-                        . '</div>'
-                    );
-                    $aForms["setup"]["form"]['input' . $i++] = array(
-                        'type' => 'text',
-                        'name' => 'phases[' . $sPhase . '][replace]['.$tTplFile.'][targetfile]',
-                        'label' => t("replacement-targetfile"),
-                        'value' => $aValues && array_key_exists('targetfile', $aValues) ? $aValues['targetfile'] : '',
-                        // 'required' => 'required',
-                        'validate' => 'isastring',
-                        'size' => 100,
-                        'placeholder' => strip_tags(t("replacement-targetfile")),
-                    );
-                    $aForms["setup"]["form"]['input' . $i++] = array(
-                        'type' => 'markup',
-                        'value' => '<br>'.t("replacement-fields") 
-                    );
-                    if(count($aFields)){
-                        foreach ($aFields as $sField){
-
-                            $aForms["setup"]["form"]['input' . $i++] = array(
-                                'type' => 'text',
-                                'disabled' => $this->oUser->hasPermission("project-action-setup-edit-replacements") ? '' : 'disabled',
-                                'name' => 'phases[' . $sPhase . '][replace]['.$tTplFile.']['.$sField.']',
-                                'label' => $sField,
-                                'value' => $aValues && array_key_exists($sField, $aValues) ? $aValues[$sField] : '',
-                                // 'required' => 'required',
-                                'validate' => 'isastring',
-                                'size' => 100,
-                                'placeholder' => $sField,
-                            );
-                        }
-                    } else {
-                        $aForms["setup"]["form"]['input' . $i++] = array(
-                            'type' => 'markup',
-                            'value' => '<br>'.$oHtml->getBox("error", t("replacement-fields-not-found"))
-                                // . '<pre>'.print_r($aValues, 1).'</pre>'
-                        );
-                    }
-                }
-                $aForms["setup"]["form"]['input' . $i++] = array(
-                    'type' => 'markup',
-                    'value' => '</div>'
-                );
-            } else {
-                $aForms["setup"]["form"]['input' . $i++] = array(
-                    'type' => 'markup',
-                    'value' => '<div class="form-group"><h4>'.t("none").'</h4></div>'
-                );
+
+            if ($aSelectForemanGroups) {
+                $aForms["setup"]["form"]['input' . $i++] = $aSelectForemanHostGroup;
             }
-            
+
             $aForms["setup"]["form"]['input' . $i++] = array(
                 'type' => 'markup',
                 'value' => ''
-                .'</div>'
+                . '</div>'
             ); // close div for active phase
-            
-            
+
+
             $aForms["setup"]["form"]['input' . $i++] = array(
                 'type' => 'markup',
                 'value' => '</td></tr></tbody></table>',
@@ -3381,8 +3492,18 @@ class project extends base {
         } // END: loop over phases
         $aForms["setup"]["form"]['input' . $i++] = array(
             'type' => 'markup',
-            'value' => '</div></div></div>'
-            . '<div style="clear: both; margin-bottom: 1em;"></div><hr>',
+            'value' => '</div>'
+            
+                . '<div class="tab-pane" id="tab4">'
+                . '<br><pre>'.print_r($this->_aPrjConfig, 1).'</pre>'
+                . '</div>'
+            
+            . '</div>'
+            . '</div>'
+            . '<div style="clear: both; margin-bottom: 1em;"></div>'
+            
+            
+            . '<hr>',
         );
         $aForms["setup"]["form"]['input' . $i++] = array(
             'type' => 'submit',
@@ -3401,7 +3522,7 @@ class project extends base {
      */
     public function renderNewProject() {
         global $aParams;
-        if (!$this->oUser->hasPermission("project-action-create")){
+        if (!$this->oUser->hasPermission("project-action-create")) {
             return $this->oUser->showDenied();
         }
 
diff --git a/public_html/deployment/classes/projectlist.class.php b/public_html/deployment/classes/projectlist.class.php
index c403b9a18f5405af2e633d809f71a138ee8f9c4b..cc0e59083a7baa6d61bd1bb7a85c01aa246348c3 100644
--- a/public_html/deployment/classes/projectlist.class.php
+++ b/public_html/deployment/classes/projectlist.class.php
@@ -58,6 +58,7 @@ class projectlist extends base{
         $sColClass = "tdphase";
 
         $oPrj1 = new project();
+        $oHtml=new htmlguielements();
 
         $sPrjFilter = '';
         $sPhaseFilter = '';
@@ -84,13 +85,24 @@ class projectlist extends base{
             }
 
             $sOut2 .= '<div class="' . $sPrj . ' ' . $sTrClass . ' prjbox"><div class="title">'
-                    . '<a href="" onclick="$(\'#prjfilter\').val(\'' . $sPrj . '\'); window.setTimeout(\'filterOverviewTable();\', 10);setview(\'extended\'); return false;" '
-                    . 'style="float: right;" '
-                    . 'title="' . t("overview-filter-hint") . '"><i class="glyphicon glyphicon-filter"></i> ' . t("overview-filter") . '</a>'
-                    . '<strong>'
-                    . '<a href="/deployment/' . $sPrj . '/" title="' . t("menu-project-home") . ' ' . $oPrj->getLabel() . '"><i class="glyphicon glyphicon-book"></i> ' . $oPrj->getLabel() . '</a>'
-                    . '</strong>'
-                    . '</div><div class="box" '
+                    .$oHtml->getLink(array(
+                        'href'=>'#',
+                        'onclick'=>'$(\'#prjfilter\').val(\'' . $sPrj . '\'); window.setTimeout(\'filterOverviewTable();\', 10);setview(\'extended\'); return false;',
+                        'style'=>'float: right;',
+                        'title'=>t("overview-filter-hint"),
+                        'icon'=>'filter',
+                        'label'=>t("overview-filter")
+                    ))
+                    .'<strong>'
+                    .$oHtml->getLink(array(
+                        'href'=>'/deployment/' . $sPrj . '/',
+                        'title'=>t("menu-project-home"). ' ' . $oPrj->getLabel(),
+                        'icon'=>'project',
+                        'label'=>'<strong>'.$oPrj->getLabel().'</strong>'
+                    ))
+                    .'</strong>'
+                    . '</div>'
+                    . '<div class="box" '
                     . 'onclick="location.href=\'/deployment/' . $sPrj . '/\'">'
                     . $oPrj->getDescription()
                     . '<br>'
@@ -98,22 +110,30 @@ class projectlist extends base{
 
             // render output
             $sOut.='
-                <tr class="' . $sPrj . ' ' . $sTrClass . '">
+                <tr class="' . $sPrj . ' ' . $sTrClass . '" '
+                    . 'ondblclick="location.href=\'/deployment/' . $sPrj . '/\'" '
+                    . 'title="'.sprintf(t("overview-hint-dblclick"),$sPrj).'">
                     <td class="prj">
-                        <strong>
-                            <a href="/deployment/' . $sPrj . '/" title="'.$oPrj->getDescription().'">
-                                <i class="glyphicon glyphicon-book"></i>
-                                ' . $oPrj->getLabel() . '
-                            </a>
-                        </strong>'
+                        <strong>'
+                        .$oHtml->getLink(array(
+                            'href'=>'/deployment/' . $sPrj . '/',
+                            'title'=>$oPrj->getDescription(),
+                            'icon'=>'project',
+                            'label'=>$oPrj->getLabel()
+                        ))
+                        .'</strong>'
                     . '    <br>' 
                     // . $oPrj->getDescription() 
                     . '</td>'
                     . '<td class="prj">'
-                    . '<a href="#" onclick="setProjectFilter(\'' . $sPrj . '\'); return false;" '
-                    . 'style="float: right;" '
-                    . 'class="btn btn-default" '
-                    . 'title="' . t("overview-filter-hint") . '"><i class="glyphicon glyphicon-filter"></i> ' . t("overview-filter") . '</a>'
+                    . $oHtml->getLinkButton(array(
+                        'href'=>'#',
+                        'onclick'=>'setProjectFilter(\'' . $sPrj . '\'); return false;',
+                        'style'=>'float: right',
+                        'title'=>t("overview-filter-hint"),
+                        'icon'=>'filter',
+                        'label'=>t("overview-filter"),
+                      ))
                     . '</td>'
                     . '<td class="prj">';
             if ($oPrj->canAcceptPhase()) {
diff --git a/public_html/deployment/inc_functions.php b/public_html/deployment/inc_functions.php
index 61f43c33d3b23c372202a8554df0d00afff88e1a..6bdcbf9990f22588dfdbe1171f833dfe29036208 100644
--- a/public_html/deployment/inc_functions.php
+++ b/public_html/deployment/inc_functions.php
@@ -120,22 +120,19 @@ if (isset($_SERVER) && is_array($_SERVER) && array_key_exists("REQUEST_URI", $_S
         $aParams[$sKey] = str_replace(array('\\', "\0", "\n", "\r", "'", '"', "\x1a"), array('\\\\', '\\0', '\\n', '\\r', "\\'", '\\"', '\\Z'), $aParams[$sKey]);
     }
 }
-$sImageBase = "/deployment/images/nuvola64x64/";
-$aImages = array(
-    'overview' => 'apps/fsview.png',
-    'project' => 'filesystems/desktop.png',
-    'action' => 'apps/aktion.png',
-    'build' => 'apps/kthememgr.png',
-);
 
 /**
  * get home link as button
  * @return string
  */
 function aHome($sClass = "btn btn-default") {
-    global $aParams;
+    global $oHtml;
     // if (!array_key_exists("prj", $aParams)) return false;
-    return '<a href="/deployment/?" class="' . $sClass . '"><i class=" glyphicon glyphicon-home"></i> ' . t("menu-overview") . '</a>';
+    return $oHtml->getLinkButton(array(
+        'href'=>'/deployment/?',
+        'icon'=>'overview',
+        'label'=>t("menu-overview"),
+    ));
 }
 
 /**
@@ -143,16 +140,22 @@ function aHome($sClass = "btn btn-default") {
  * @return string
  */
 function aPrjHome($sClass = "btn btn-default") {
-    global $aParams, $aConfig;
-    if (!array_key_exists("prj", $aParams))
+    global $aParams, $oHtml;
+    if (!array_key_exists("prj", $aParams)){
         return false;
-    if ($aParams["prj"] == "all")
+    }
+    if ($aParams["prj"] == "all"){
         return aHome($sClass);
+    }
     // if (!array_key_exists("action", $aParams)) return false;
 
     require_once("./classes/project.class.php");
     $oPrj = new project($aParams["prj"]);
-    return '<a href="/deployment/' . $aParams["prj"] . '/" class="' . $sClass . '"><i class=" glyphicon glyphicon-book"></i> ' . t("menu-project-home") . ' <strong>' . $oPrj->getLabel() . '</strong></a>';
+    return $oHtml->getLinkButton(array(
+        'href'=>'/deployment/' . $aParams["prj"] . '/',
+        'icon'=>'project-home',
+        'label'=>$oPrj->getLabel(),
+    ));
 }
 
 /**
@@ -160,14 +163,28 @@ function aPrjHome($sClass = "btn btn-default") {
  * @return string
  */
 function aGoback($sClass = "btn btn-default") {
-    return '<a href="#" onclick="history.back();" class="' . $sClass . '" title="' . t("back") . '"><i class="glyphicon glyphicon-chevron-left"></i> ' . t("back") . '</a> ';
+    global $oHtml;
+    return $oHtml->getLinkButton(array(
+        'href'=>'#',
+        'onclick'=>'history.back();',
+        'title'=>t("back"),
+        'icon'=>'back',
+        'label'=>t("back")
+    ));
 }
 /**
  * get go top link as button
  * @return string
  */
 function aGotop($sClass = "scroll-link btn btn-default") {
-    return '<a href="#top" class="' . $sClass . '" title="' . t("gotop") . '"><i class=" glyphicon glyphicon-eject"></i> </a> ';
+    global $oHtml;
+    return $oHtml->getLinkButton(array(
+        'href'=>'#top',
+        'class'=>$sClass,
+        'title'=>t("gotop"),
+        'icon'=>'glyphicon-eject',
+        'label'=>' '
+    ));
 }
 
 /**
@@ -176,7 +193,7 @@ function aGotop($sClass = "scroll-link btn btn-default") {
  * @return type
  */
 function getTopArea() {
-    global $aParams, $sImageBase, $aImages, $aConfig;
+    global $aParams, $oHtml;
     $sReturn = '';
     require_once("./classes/project.class.php");
     require_once("./classes/user.class.php");
@@ -219,30 +236,67 @@ function getTopArea() {
               <ul class="nav navbar-nav">
               
                 <li class="dropdown';
-                if (!array_key_exists("prj", $aParams)){
+                if (array_key_exists("prj", $aParams) && $aParams['prj']==='all'){
                     $sReturn.=' active';
                 }
                 $sReturn.='">'
-                        . '<a href="' . $sBaseUrl . '" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"
-                  >'.t("menu-overview").' <span class="caret"></span></a>
-                  <ul class="dropdown-menu" role="menu">
-                    <li><a href="' . $sBaseUrl . 'all/setup/">' . t("menu-settings") . '</a></li>
-                    <li><a href="' . $sBaseUrl . 'all/setup/actionlog/">' . t("menu-logs") . '</a></li>
-                    <li><a href="' . $sBaseUrl . 'all/setup/new/">' . t("menu-new-project") . '</a></li>
+                        . $oHtml->getLink(array(
+                            'href'=>$sBaseUrl,
+                            'class'=>'dropdown-toggle',
+                            'data-toggle'=>'dropdown',
+                            'role'=>'button',
+                            'aria-expanded'=>'false',
+                            'icon'=>'menu',
+                            'label'=>t("menu").' <span class="caret"></span>',
+                        ))
+                  .'<ul class="dropdown-menu" role="menu">
+                    <li>'.$oHtml->getLink(array(
+                            'href'=>$sBaseUrl . 'all/setup/new/',
+                            'icon'=>'new',
+                            'label'=>t("menu-new-project"),
+                        )).'</li>
+                    <li>'.$oHtml->getLink(array(
+                            'href'=>$sBaseUrl . 'all/setup/actionlog/',
+                            'icon'=>'actionlog',
+                            'label'=>t("menu-logs"),
+                        )).'</li>
+                    <li>'.$oHtml->getLink(array(
+                            'href'=>$sBaseUrl . 'all/setup/checklang/',
+                            'icon'=>'checklang',
+                            'label'=>t("menu-checklang"),
+                        )).'</li>
+                    <li>'.$oHtml->getLink(array(
+                            'href'=>$sBaseUrl . 'all/setup/',
+                            'icon'=>'setup',
+                            'label'=>t("menu-settings"),
+                        )).'</li>
                   </ul>
                 </li>
                 
 
-                <li class="dropdown">
-                   <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"
-                   >' . t("menu-projects") . ' <span class="caret"></span></a>
-                  <ul class="dropdown-menu" role="menu">
-                    ';
+                <li class="dropdown">'
+                    . $oHtml->getLink(array(
+                        'href'=>'#',
+                        'class'=>'dropdown-toggle',
+                        'data-toggle'=>'dropdown',
+                        'role'=>'button',
+                        'aria-expanded'=>'false',
+                        'icon'=>'projects',
+                        'label'=>t("menu-projects") . ' <span class="caret"></span>',
+                    ))
+                    .'<ul class="dropdown-menu" role="menu">'
+                    ;
                 
                     $oPrj1 = new project();
                     foreach ($oPrj1->getProjects() as $sPrj) {
                         $oPrj = new project($sPrj);
-                        $sReturn.='<li><a href="' . $sBaseUrl . $sPrj . '/">' . $oPrj->getLabel() . '</a></li>';
+                        $sReturn.='<li>'
+                                . $oHtml->getLink(array(
+                                    'href'=>$sBaseUrl . $sPrj .'/',
+                                    'icon'=>'project',
+                                    'label'=>$oPrj->getLabel(),
+                                ))
+                                . '</li>';
                     }
                     $sReturn.='
                   </ul>
@@ -252,55 +306,106 @@ function getTopArea() {
                 if (array_key_exists("prj", $aParams) && $aParams["prj"] <> "all") {
                     $oPrj = new project($aParams["prj"]);
                     $sReturn.='
-                                <li class="active">' . aPrjHome(" ") . '</li>
-                                ';
-                    if (array_key_exists("action", $aParams) and FALSE) {
-                        $sReturn.='<li><a href="#">Aktion: ' . $aParams["action"] . '</a></li>';
-                    } else {
-                        $sReturn.='
-                                    <li class="dropdown">
-                                        <a href="' . $sBaseUrl . '" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"
-                                        >'.t("menu-project-actions").' <span class="caret"></span></a>
-
-                                    <ul class="dropdown-menu" role="menu">
-                                        <!--
-                                        <li><a href="' . $sBaseUrl . $aParams["prj"] . '/build/">' . t("menu-project-build") . '</a></li>
-                                        -->
-                                        <li><a href="' . $sBaseUrl . $aParams["prj"] . '/setup/">' . t("menu-project-settings") . '</a></li>
-                                        <li><a href="' . $sBaseUrl . $aParams["prj"] . '/cleanup/">' . t("menu-project-cleanup") . '</a></li>
-                                        <li><a href="' . $sBaseUrl . $aParams["prj"] . '/delete/">' . t("menu-project-delete") . '</a></li>
-                                    ';
-                        $sReturn.='</ul></li>';
-
+                    <li class="dropdown active">'
+                        .$oHtml->getLink(array(
+                            'href'=>'#',
+                            'class'=>'dropdown-toggle',
+                            'data-toggle'=>'dropdown',
+                            'role'=>'button',
+                            'aria-expanded'=>'false',
+                            'icon'=>'project',
+                            'label'=>$oPrj->getLabel() .' <span class="caret"></span>',
+                        ))
+                        .'
+                        <ul class="dropdown-menu" role="menu">
+                            <li>'
+                            . $oHtml->getLink(array(
+                                'href'=>$sBaseUrl . $sPrj .'/',
+                                'icon'=>'project-home',
+                                'label'=>t("project-home"),
+                            ))
+                            .'</li>
+                        ';
                         $aPhases = $oPrj->getActivePhases();
                         if (count($aPhases)) {
-                            $sReturn.='<li class="dropdown"">
-                                            <a href="#" class="dropdown-toggle" data-toggle="dropdown">' . t("menu-project-phases") . '<b class="caret"></b></a>
-                                            <ul class="dropdown-menu"  role="menu">';
+                            $sReturn.='<li role="separator" class="divider"></li>
+                                    <li>'
+                                    .$oHtml->getLink(array(
+                                        'href'=>$sBaseUrl . $aParams["prj"] . '/build/',
+                                        'icon'=>'build',
+                                        'label'=>t("build"),
+                                    ))
+                                    .'</li> 
+                                    <li role="separator" class="divider"></li>
+                                    <li class="dropdown-header">'.t("menu-project-phases").'</li>';
                             foreach ($aPhases as $sPhase) {
-                                $sReturn.='<li><a href="' . $sBaseUrl . $aParams["prj"] . '/phase/' . $sPhase . '/">' . $sPhase . '</a></li>';
+                                $sReturn.='<li><a href="' . $sBaseUrl . $aParams["prj"] . '/phase/' . $sPhase . '/">' . $oHtml->getIcon('phase').$sPhase . '</a></li>';
                             }
-                            $sReturn.='</ul></li>';
                         }
-                    }
+                        $sReturn.='
+                            <li role="separator" class="divider"></li>
+                            <li>'
+                            .$oHtml->getLink(array(
+                                'href'=>$sBaseUrl . $aParams["prj"] . '/setup/',
+                                'icon'=>'setup',
+                                'label'=>t("menu-project-settings"),
+                            ))
+                            .'</li> 
+                            <li>'
+                            .$oHtml->getLink(array(
+                                'href'=>$sBaseUrl . $aParams["prj"] . '/cleanup/',
+                                'icon'=>'cleanup',
+                                'label'=>t("menu-project-cleanup"),
+                            ))
+                            .'</li> 
+                            <li>'
+                            .$oHtml->getLink(array(
+                                'href'=>$sBaseUrl . $aParams["prj"] . '/delete/',
+                                'icon'=>'delete',
+                                'label'=>t("menu-project-delete"),
+                            ))
+                            .'</li> 
+                        </ul></li>';
                 }
     }
                     
             $sReturn.='
               </ul>
             
-            <ul class="nav navbar-nav navbar-right">
+            <ul class="nav navbar-nav navbar-right">'
+                . ($oUser->getUsername() 
+                    ? '
                     <!-- userdata -->
-                    <li class="dropdown">
-                        <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"
-                        ><span class="glyphicon glyphicon-user"></span> ' . $oUser->getUsername() . ' <b class="caret"></b></a>
-                        <ul class="dropdown-menu" role="menu">
-                            <li><a href="' . $sBaseUrl . 'all/login/">' . t("menu-login") . '</a></li>
+                    <li class="dropdown">'
+                        .$oHtml->getLink(array(
+                            'href'=>'#',
+                            'class'=>'dropdown-toggle',
+                            'data-toggle'=>'dropdown',
+                            'role'=>'button',
+                            'aria-expanded'=>'false',
+                            'icon'=>'user',
+                            'label'=>$oUser->getUsername() .' <span class="caret"></span>',
+                        ))
+                        .'<ul class="dropdown-menu" role="menu">
+                            <li>'
+                            .$oHtml->getLink(array(
+                                'href'=>$sBaseUrl . 'all/login/',
+                                'icon'=>'login',
+                                'label'=>t("menu-login"),
+                            ))
+                            .'</li> 
                         </ul>
-                    </li>
-
-
-                    <li class="dropdown">
+                    </li>'
+                        
+                    : '<li>'
+                        .$oHtml->getLink(array(
+                            'href'=>$sBaseUrl . 'all/login/',
+                            'icon'=>'login',
+                            'label'=>t("login"),
+                        ))
+                      .'</li>'
+                )
+                .'<li class="dropdown">
                         <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"
                         ><span class="glyphicon glyphicon-question-sign"></span> ' . t("menu-help") . ' <b class="caret"></b></a>
                         <ul class="dropdown-menu">
@@ -320,13 +425,12 @@ function getTopArea() {
         </div><div id="header2">';
 
     if (!array_key_exists("prj", $aParams)) {
-        $sReturn.='<!-- <img src="' . $sImageBase . $aImages['overview'] . '" id="imgtop" alt=""> -->'
-                . '<h1>' . t("overview-label") . '</h1><span class="description">' . t("overview-hint") . '</span>';
+        $sReturn.='<h1>' . t("overview-label") . '</h1><span class="description">' . t("overview-hint") . '</span>';
     } else {
         if ($aParams["prj"] <> "all") {
             $oPrj = new project($aParams["prj"]);
-            $sReturn.='<!-- <img src="' . $sImageBase . $aImages['project'] . '" id="imgtop" alt="">-->
-                <h1>' . $oPrj->getLabel() . '</h1><span class="description">' . $oPrj->getDescription() . '</span>';
+            $sReturn.='<h1>' . $oPrj->getLabel() . '</h1>'
+                    . '<span class="description">' . $oPrj->getDescription() . '</span>';
             if (array_key_exists("action", $aParams)) {
                 // $sReturn.='<h2>Aktion: '.$aParams["action"].'</h2>';
             }
@@ -340,22 +444,38 @@ function getTopArea() {
 /**
  * get h2 headline with action
  * @global type $aParams
- * @global string $sImageBase
- * @global array $aImages
  * @return string
  */
 function getAction() {
-    global $aParams, $sImageBase, $aImages;
+    global $aParams, $oHtml;
     $sReturn = '';
+    $sNav = '';
+    $sLabel = '';
+    // $sDelim=$oHtml->getIcon('fa-chevron-right');
+    $sDelim=' / ';
     if (array_key_exists("action", $aParams)) {
-        $sLabel = $aParams["action"];
+        $sLabel .= $oHtml->getIcon($aParams["action"]).t($aParams["action"]);
+        $sNav .= aHome();
+        if ($aParams['prj']==='all'){
+            // $sNav .= ' ' . $oHtml->getIcon('fa-chevron-right') . '[ci-GUI]';
+        } else {
+            $sNav .= ' ' . $sDelim . aPrjHome();
+        }
+        $sClass='action '.$aParams["action"];
         if (array_key_exists("par3", $aParams)) {
-            $sLabel.=' :: ' . $aParams["par3"];
+            $sLabel.=' :: ' . $oHtml->getIcon($aParams["par3"]). $aParams["par3"];
+            $sClass='action ' . $aParams["action"];
         }
-        $sReturn.='<h2 class="action ' . $aParams["action"] . '">' . $sLabel . '</h2>';
+        // $sReturn.='<h2 class="action ' . $aParams["action"] . '">' . $sLabel . '</h2>';
     } else if (array_key_exists("prj", $aParams)) {
-        $sReturn.='<h2 class="action prjhome"> Projekt-Home</h2>';
+        $sNav .= aHome();
+        $sClass='action prjhome';
+        $sLabel.=$oHtml->getIcon('project-home').t('project-home');
+        // $sReturn.='<h2 class="action prjhome"> Projekt-Home</h2>';
     }
+    $sReturn.=($sNav ? '<div id="navtop">' . $sNav .  ' ' . $sDelim . ' <span class="current">'.$sLabel.'</span></div>':'')
+        // .'<h2 class="'.$sClass.'"> '.$sLabel.'</h2>'
+        ;
     return $sReturn;
 }
 
diff --git a/public_html/deployment/main.css b/public_html/deployment/main.css
index 342dc40172d9fd7b0910a0f25b699b68aef26434..57a224df6125ef7abe49ee29e0d9a40aed7f3a39 100644
--- a/public_html/deployment/main.css
+++ b/public_html/deployment/main.css
@@ -42,11 +42,18 @@ body{padding-top: 0;}
     border-left: 0px solid #ccc;
     padding: 1em;
     box-shadow: 0 0 15px #eee;
+
+    padding: 0.5em;
+    box-shadow: 0 0 7em #ddd;
 }
 
+div#navtop, div#navbuttom{background: #dde; padding: 0.5em;}
+div#navtop{margin-bottom: 2em;}
+div#navtop .current{font-size: 170%; color: #667; padding: 0 0.2em; position: absolute;}
 div#navbuttom{
-    margin-top: 4em; padding: 1em 0; 
-    border-top: 2px solid #ddd;}
+    margin-top: 4em; 
+    border-top: 2px solid #ddd;
+}
 
 #divmodal{
     position: fixed; height: 100%; width: 100%; top:0; left:0;
@@ -80,7 +87,7 @@ h2.phase{background-image: url("/deployment/images/nuvola64x64/apps/kreversi.png
 h2.setup{background-image: url("/deployment/images/nuvola64x64/apps/kcmsystem.png");}
 h2.login{background-image: url("/deployment/images/nuvola64x64/apps/kgpg.png");}
 */
-h3{color:#444; margin-top: 3em;}
+h3{background: #f0f0f4; color:#456; margin: 3em 0 1em; padding: 0.5em;}
 h3:first-child{margin-top: 0;}
 
 h4{color:#666;}
@@ -238,6 +245,8 @@ input[type="radio"]:checked+label, input[type="checkbox"]:checked+label{
 .visualprocess .process .title{margin-bottom: 2em; font-weight: bold; font-size: 150%; color:#aaa;}
 .visualprocess .process .details{background: #fff; min-height: 6em;}
 
+/* ----- replacemets with templates ----- */
+span.replace{background:#fea; font-weight: bold;}
 
 /* ----- log table ----- */
 .loglevel-info{}
diff --git a/public_html/deployment/pages/act_build.php b/public_html/deployment/pages/act_build.php
index 9fbeee728a192211fbdbf7502b53fbeaa5eb5ee0..996de19faa9b3eb9f29caa7529950ef6a86ec2ea 100644
--- a/public_html/deployment/pages/act_build.php
+++ b/public_html/deployment/pages/act_build.php
@@ -57,9 +57,9 @@ if (!array_key_exists("confirm", $aParams)) {
         <table>
              <thead>
                  <tr>
-                     <th class="versioncontrol" colspan="2">' . t("versioncontrol") . '</th>
+                     <th class="versioncontrol" colspan="2">' . $oHtml->getIcon('repository').t("versioncontrol") . '<br></th>
                      <th> </th>
-                     <th class="' . $sNext . '" colspan="2">' . $sNext . '</th>
+                     <th class="' . $sNext . '" colspan="2">' . $oHtml->getIcon('phase').$sNext . '</th>
                  </tr>
              </thead>
              <tbody>
diff --git a/public_html/deployment/pages/act_htmltest.php b/public_html/deployment/pages/act_htmltest.php
index 51ac13853360d4c169b5862836f018321b043d94..3188f31ceaee2d260204a4d9c95bd33f22e6ee99 100644
--- a/public_html/deployment/pages/act_htmltest.php
+++ b/public_html/deployment/pages/act_htmltest.php
@@ -96,6 +96,16 @@ $sRows=''
         ),
     )
 );")
+   .  addHtmltestTest("Tabelle", "\$oHtml->getTable(
+    array(
+        'header'=>array('A', 'B'), 
+        'body'=>array(
+            array('Zelle A 1', 'Zelle B 1'),
+            array('Zelle A 2', 'Zelle B 2'),
+            array('Zelle A 3', 'Zelle B 3'),
+        ),
+));"
+)
 ;
 
 // ----------------------------------------------------------------------
diff --git a/public_html/deployment/pages/act_login.php b/public_html/deployment/pages/act_login.php
index f0ca82f02574cebe7a0a7b91f220c0c1f8435553..0c6634a96435eb818f82947df5c8b9c220ea8f60 100644
--- a/public_html/deployment/pages/act_login.php
+++ b/public_html/deployment/pages/act_login.php
@@ -127,7 +127,7 @@ if ($oUser->getUsername()) {
     );
 
     $oForm = new formgen($aForms);
-    $sOut.='<div style="width: 50%; margin-left: 25%;">'
+    $sOut.='<div style="width: 50%; min-width: 60em; margin-left: 15%;">'
             . '<h2>' . t("page-login-info") . '</h2>'
             . '<p>' . t("page-login-info-introtext") . '</p>';
     if (array_key_exists('user', $aParams)) {
diff --git a/public_html/deployment/pages/act_overview.php b/public_html/deployment/pages/act_overview.php
index 48ccb45ac70c8f4ef775d7f6f43a3a013e760f0c..8bff0dd4ec78ddbfade22fbce36ca92fc5e0062b 100644
--- a/public_html/deployment/pages/act_overview.php
+++ b/public_html/deployment/pages/act_overview.php
@@ -47,20 +47,20 @@ if (!array_key_exists("prj", $aParams)) {
                 <br>
         
             <ul class="nav nav-tabs">
-                <li class="active"><a href="#tab1" data-toggle="tab">' . t("way-of-packages") . '</a></li>
-                <li><a href="#tab2" data-toggle="tab">' . t("repositoryinfos") . '</a></li>
-                <li><a href="#tab3" data-toggle="tab">' . t("packages") . '</a></li>
-                <li><a href="#tab4" data-toggle="tab">' . t('phases') . '</a></li>
+                <li class="active"><a href="#tab1" data-toggle="tab">' . $oHtml->getIcon('workflow') . t("way-of-packages") . '</a></li>
+                <li><a href="#tab2" data-toggle="tab">' . $oHtml->getIcon('repository') . t("repositoryinfos") . '</a></li>
+                <li><a href="#tab3" data-toggle="tab">' . $oHtml->getIcon('package') . t("packages") . '</a></li>
+                <li><a href="#tab4" data-toggle="tab">' . $oHtml->getIcon('phase') . t('phases') . '</a></li>
             </ul>
             <br>
             <div class="tab-content">
                 <div class="tab-pane active" id="tab1">
                     '
-                    . '<h3 id="h3visual">' . t("way-of-packages") . '</h3>
+                    . '<h3 id="h3visual">' . $oHtml->getIcon('workflow') . t("way-of-packages") . '</h3>
                     ' . $oPrj->renderVisual() . '
                 </div>
                 <div class="tab-pane" id="tab2">
-                    <h3 id="h3repo">' . t("repositoryinfos") . '</h3>
+                    <h3 id="h3repo">' . $oHtml->getIcon('repository') . t("repositoryinfos") . '</h3>
                         <div style="max-width: 40em;">
                         ' . $oPrj->renderRepoInfo() . '
                         ' . $sListOfBranches . '
@@ -69,13 +69,13 @@ if (!array_key_exists("prj", $aParams)) {
                 </div>
                 
                 <div class="tab-pane" id="tab3">
-                    <h3 id="h3versions">' . t("packages") . '</h3>
+                    <h3 id="h3versions">' . $oHtml->getIcon('package') . t("packages") . '</h3>
                     ' . $oPrj->renderVersionUsage() .'
    
                 </div>
                 <div class="tab-pane" id="tab4">
                     
-                    <h3 id="h3phases">' . t("phases") . '</h3>
+                    <h3 id="h3phases">' . $oHtml->getIcon('phase') . t("phases") . '</h3>
                     '.($oPrj->getActivePhases()
                             ? '<p>' 
                                 . t("page-overview-phase-infos") 
diff --git a/public_html/deployment/pages/act_phase.php b/public_html/deployment/pages/act_phase.php
index c93965e3c38f98e5187a7143348b80cccccb75ac..ff97695c3fb5cfe4ec2186bd31b4838ccd47b187 100644
--- a/public_html/deployment/pages/act_phase.php
+++ b/public_html/deployment/pages/act_phase.php
@@ -13,6 +13,7 @@
 
 require_once("./classes/project.class.php");
 require_once("./inc_functions.php");
+require_once("./classes/config-replacement.class.php");
 
 
 // --- Checks
@@ -24,11 +25,209 @@ if (array_key_exists("par3", $aParams)) {
 }
 
 if ($sPhase) {
-    $sPhase = $aParams["par3"];
-    // $sFirst = $oPrj->getNextPhase();
+    $aWarnings=array();
+    $sOutReplace='';
+    
+    // ----------------------------------------------------------------------
+    // replacement
+    // ----------------------------------------------------------------------
+    
+    $oConfig = new configreplacement();
+    $oConfig->setProject($aParams["prj"], $sPhase);
+
+    $aReplacements=$oConfig->getReplacements();
+
+    $sOut.='<h3>' . $oHtml->getIcon('replace') . t("replacements") . '</h3>';
+
+    // ----------------------------------------------------------------------
+    // Links to foreman
+    // ----------------------------------------------------------------------
+    $aForeman=$oConfig->getForemanReplacements();
+    $aReplacementsForeman=$aForeman ? $aForeman['rules'] : false;
+    
+    // echo '<pre>$aReplacements = '.print_r($aReplacements, 1) . '</pre>';
+    // echo '<pre>$aForeman = '.print_r($aForeman, 1) . '</pre>';
+
+    $sOut.=($aReplacementsForeman
+            ? $oConfig->getForemanlink2Hostgroup().' '
+                .$oConfig->getForemanlink2Host()
+            : t('foreman-no-host')
+            ).'<br><br>'
+        ;
+
+    // ----------------------------------------------------------------------
+    // Loop over files
+    // ----------------------------------------------------------------------
+
+    if ($aReplacements) {
+        
+        // open all/ close all
+        if(count($aReplacements)>1){
+            $sOutReplace.=$oHtml->getLinkButton(array(
+                'onclick'=>'$(\'.divfileinfos\').slideDown(); $(\'.expandable\').removeClass(\'closed\'); this.blur(); return false;',
+                'icon'=>'fa-chevron-down',
+            ))
+            .$oHtml->getLinkButton(array(
+                'onclick'=>'$(\'.divfileinfos\').slideUp(); $(\'.expandable\').addClass(\'closed\'); this.blur(); return false;',
+                'icon'=>'fa-chevron-up',
+            ))
+            ;
+        }
+        
+        foreach ($aReplacements as $sFile => $aFields) {
+            $tTplFile = basename($sFile);
+            $bFileInForeman = $aReplacementsForeman && array_key_exists($tTplFile, $aReplacementsForeman);
+            $sDivIdFile='div4file-'.md5($sFile);
+
+            $sOutReplace.='<h4>' . 
+                    $oHtml->getLink(array(
+                        'onclick'=>'$(\'#'.$sDivIdFile.'\').slideToggle(); $(this).toggleClass(\'closed\'); return false;',
+                        'class'=>'expandable closed',
+                        'icon'=>'templatefile',
+                        'label'=>$tTplFile,
+                    )) . '</h4>'
+                    . '<div id="'.$sDivIdFile.'" class="divfileinfos" style="display: none;">'
+                    ;
+
+            // --- check: does this file in foreman exist?
+            if (!array_key_exists($tTplFile, $aReplacementsForeman)){
+                if ($aReplacementsForeman){
+                    $sOutReplace.=$oHtml->getBox('error', t('foreman-error-template-unknown'));
+                    $aWarnings[]=$tTplFile.': '.t('foreman-error-template-unknown');
+                }
+            }
+
+
+            // --- check: target file was set?
+            $aTable=array('header'=>array(), 'body'=>array());
+            if ($bFileInForeman){
+                if ($aReplacementsForeman && array_key_exists('target', $aReplacementsForeman[$tTplFile])){
+                    $sTd='<strong>'.$oHtml->getIcon('targetfile') . $aReplacementsForeman[$tTplFile]['target'].'</strong>';
+                } else {
+                    if ($bFileInForeman){
+                        $sTd=t('foreman-error-no-target');
+                        $aWarnings[]=$tTplFile.': '.t('foreman-error-no-target');
+                    } else {
+                        $sTd='-';
+                    }
+                }
+                $aTable['body'][]=array(
+                    $oHtml->getIcon('templatefile') . t('foreman-targetfile'), 
+                    $sTd
+                );
+            }
+
+            // --- loop over all replacement items of template file
+            //     and check if they exist in foreman
+            if (count($aFields)) {
+                foreach ($aFields as $sField){
+                    if ($aReplacementsForeman && array_key_exists($sField, $aReplacementsForeman[$tTplFile]['replace'])){
+                        $sTd=$aReplacementsForeman[$tTplFile]['replace'][$sField];
+                    } else {
+                        if ($bFileInForeman){
+                            $sTd=$oHtml->getBox('error', sprintf(t('foreman-error-no-replacement-for-id'), $sField));
+                            $aWarnings[]=$tTplFile.': '.sprintf(t('foreman-error-no-replacement-for-id'), $sField);
+                        } else {
+                            $sTd='-';
+                        }
+
+                    }
+                    $aTable['body'][]=array(
+                        $oHtml->getIcon('replace') . $sField, 
+                        $sTd
+                    );
+                }
+            } else {
+                $aTable['body'][]=array(
+                    $oHtml->getBox('error', t('foreman-error-no-replacement-in-templatefile')),
+                    '-'
+                );
+                $aWarnings[]=$tTplFile.': '.t('foreman-error-no-replacement-in-templatefile');
+            }
+
+            // --- reverse check ... loop over all replacement items of foreman
+            //     and check if they exist in template
+            if ($aReplacementsForeman){
+                // for testing: create a testvalue
+                // $aReplacementsForeman[$tTplFile]['replace']['testentry']='dummy value';
+                foreach ($aReplacementsForeman[$tTplFile]['replace'] as $sField=>$sValue){
+                    if (array_search($sField, $aFields)===false){
+                        $aTable['body'][]=array(
+                            $oHtml->getIcon('replace') . 
+                            $oHtml->getBox('error', sprintf(t('foreman-error-replacement-unknown'), $sField)),
+                            $sValue
+                        );
+                        $aWarnings[]=$tTplFile.': '. sprintf(t('foreman-error-replacement-unknown'), $sField);
+                    }
+                }
+            }
+
+            // --- filecontent of template
+            $ContentFile='<br>'.$sFile.'<br><br>'
+                    .'<pre style="max-height:35em;">'
+                    . preg_replace('/(@replace\[.*\])/U', '<span class="replace">${1}</span>' , htmlentities(file_get_contents($sFile)))
+                    .'</pre>';
+
+            // --- output with tabs for a template file
+            $sOutReplace.=$oHtml->getNav(
+                array(
+                    'options'=>array('type'=>'tabs'),
+                    'tabs'=>array(
+                        $oHtml->getIcon('list') . t('replacement-fields') => '<br>'.$oHtml->getTable($aTable),
+                        $oHtml->getIcon('templatefile') . $tTplFile => $ContentFile,
+                    )                    
+                )
+            )
+            .'<br></div>';
+        }
+    } else {
+        $sOutReplace.=t('none');
+    }
+    
+    
+    // --- reverse check - do templates in foreman physically exist?
+    // for testing: create a testfile
+    // $aReplacementsForeman['dummytemplate.erb']=array();
+    if($aReplacementsForeman){
+        foreach(array_keys($aReplacementsForeman) as $sForemanTemplate){
+            
+            $bFound=false;
+            foreach (array_keys($aReplacements) as $sFile) {
+                if (basename($sFile)===$sForemanTemplate){
+                    $bFound=true;
+                    continue;
+                }
+            }
+            if (!$bFound){
+                $aWarnings[]=sprintf(t('foreman-error-missing-template'), $sForemanTemplate);
+                $sDivIdFile='div4file-'.md5($sForemanTemplate);
+
+                $sOutReplace.='<h4>' . 
+                        $oHtml->getLink(array(
+                            'onclick'=>'$(\'#'.$sDivIdFile.'\').slideToggle(); $(this).toggleClass(\'closed\'); return false;',
+                            'class'=>'expandable closed',
+                            'icon'=>'fa-warning',
+                            'label'=>$sForemanTemplate,
+                        )) . '</h4>'
+                        . '<div id="'.$sDivIdFile.'" class="divfileinfos" style="display: none;">'
+                        .$oHtml->getBox('error', sprintf(t('foreman-error-missing-template'), $sForemanTemplate))
+                        . '</div>'
+                        ;
+
+            }
+        }
+    }
 
+    if (count($aWarnings)){
+        $sOut.=$oHtml->getBox('warning', '<ul><li>'.implode('<li>', $aWarnings).'</ul>');
+    }
+    $sOut.=$sOutReplace;
+    
+    // ----------------------------------------------------------------------
+    // versions
+    // ----------------------------------------------------------------------
     $sOut.='
-    <h3>' . t("versions") . '</h3>
+    <h3>' . $oHtml->getIcon('version').t("versions") . '</h3>
     <table>
      <thead>
          <tr>
@@ -42,10 +241,15 @@ if ($sPhase) {
         </tr>
      </tbody>
     </table>
-    '
+    ';
+    
+    // ----------------------------------------------------------------------
+    // list of phases
+    // ----------------------------------------------------------------------
+    
     // show all  phases if there are more than one
-    . (count($oPrj->getActivePhases())>1
-        ? '<h3>' . t("phases") . '</h3>' .  $oPrj->renderPhaseInfo()
+    $sOut.=(count($oPrj->getActivePhases())>1
+        ? '<h3>' . $oHtml->getIcon('phase').t("phases") . '</h3>' .  $oPrj->renderPhaseInfo()
         : ''
     )
     ;
diff --git a/public_html/deployment/pages/act_setup.php b/public_html/deployment/pages/act_setup.php
index 7fc8f3110dde77f47babf10876c38581b0ef3480..b231c42b0508915c5375d61aff3675a16813a8fd 100644
--- a/public_html/deployment/pages/act_setup.php
+++ b/public_html/deployment/pages/act_setup.php
@@ -16,6 +16,45 @@ require_once("./classes/project.class.php");
 require_once("./inc_functions.php");
 $sOut = '';
 
+$sFakePassword='********************';
+
+// items to mask
+$aMask=array(
+    'auth'=>array(
+        'ldap'=>array(
+            'PwLdapUser'=>$sFakePassword
+        )
+    ),
+    'foreman'=>array(
+        'password'=>$sFakePassword
+    ),
+    'projects'=>array(
+        'ldap'=>array(
+            'PwLdapUser'=>$sFakePassword
+        )
+    ),
+);
+
+/**
+ * hide entries in config array
+ * @param type $aMask
+ * @param type $aConfig
+ * @return type
+ */
+function maskEntries($aMask, $aConfig){
+    foreach ($aMask as $sKey=>$aValue){
+        
+        if (array_key_exists($sKey, $aConfig)){
+            $aConfig[$sKey]=(is_array($aValue)
+                    ? maskEntries($aMask[$sKey], $aConfig[$sKey])
+                    : $aMask[$sKey]
+            )
+            ;
+        }
+    }
+    return $aConfig;
+}
+
 if ($aParams["prj"] == "all") {
     
     // ------------------------------------------------------------
@@ -23,14 +62,10 @@ if ($aParams["prj"] == "all") {
     // ------------------------------------------------------------
     if (!array_key_exists("par3", $aParams)) {
         $oPrj = new project();
-        $sOut.='<h2>'.t("page-setup-info").'</h2>'
-                . '<p>'.t("page-setup-info-introtext").'</p>'
-                . '<p>'
-                . '<a href="./checklang/">'.t("page-setup-info-check-lang").'</a><br>'
-                . '<a href="./actionlog/">'.t("class-actionlog-title").'</a><br>'
-                . '</p>';
-        
+        $aTmp=maskEntries($aMask, $aConfig);
+        $sOut.= '<pre>'.print_r($aTmp, 1).'</pre>';
         
+        // print_r($aConfig);
         $i = 0;
         require_once ("./classes/formgen.class.php");
         
@@ -258,7 +293,7 @@ if ($aParams["prj"] == "all") {
 
     if (array_key_exists("setupaction", $aParams) && $aParams["setupaction"] == "save") {
         if ($oPrj->saveConfig()) {
-            $sOut.=$oHtml->getBox("success", t("page-setup-info-settings-were-saved")) . aPrjHome() . '<br><br>';
+            $sOut.=$oHtml->getBox("success", t("page-setup-info-settings-were-saved"));
         } else {
             $sOut.=$oHtml->getBox("error", t("page-setup-error-settings-were-not-saved"));
         }
diff --git a/public_html/vendor/shooker/shooker.php b/public_html/vendor/shooker/shooker.php
new file mode 100644
index 0000000000000000000000000000000000000000..b042bb7956478e32379fdc7e94cd9772da314b1e
--- /dev/null
+++ b/public_html/vendor/shooker/shooker.php
@@ -0,0 +1,164 @@
+<?php
+/*------------------------------------------------------------------------
+ *  shooker.php
+ *  Created by: John Wenzler (nnullandvoidd@gmail.com)
+ *  Available under the MIT License
+ *  FOR MORE INFO AND EXAMPLES, VISIT:
+ *     https://github.com/jwenzler/Shooker
+ * 
+ ------------------------------------------------------------------------*/
+
+class Shooker {
+  
+  //No error by default
+  private $error = false;
+  private $errorMessages = array();
+  
+  //Token to make sure the request is coming from Slack
+  private $token = null;
+  
+  //Incoming Slack endpoint
+  private $incomingURL = null;
+  
+  //Text to send back to Slack client
+  private $responseText = null;
+  
+  //Trigger array
+  private $triggers;
+  
+  function __constructNoToken() {
+    $this->triggers = new stdClass;
+  } 
+  
+  function setupIncoming($incomingURL) {
+    $this->incomingURL = $incomingURL;
+  }
+  
+  function setupOutgoing($token) {
+    $this->token = $token;
+  }
+  
+  function addTrigger($triggerWord) {
+    $trigger = new ShookerTrigger($triggerWord);
+    $this->triggers->{$triggerWord} = $trigger;
+    return $trigger;
+  }
+  
+  function sendMessage($message, $username, $icon) {
+    $data = array(
+        'text' => $message
+    );
+    
+    if (isset($username)) {
+      $data['username'] = $username;
+    }
+    
+    if (isset($icon)) {
+      $data['icon_emoji'] = $icon;
+    }
+    
+    $options = array(
+      'http' => array(
+        'header'  => 'Content-type: application/x-www-form-urlencoded\r\n',
+        'method'  => 'POST',
+        'content' => json_encode($data)
+      )
+    );
+
+    $context  = stream_context_create($options);
+    $result = file_get_contents($this->incomingURL, false, $context);
+    
+    return $result;
+  }
+  
+  //Calculate response text and send it back to the Slack client
+  function listen() {
+    
+    //Retrieve the text inbound to the webhook
+    $inText = $_POST['text'];
+    //Retrieve the user name for the sent in message
+    $inUser = $_POST['user_name'];
+    //Retrieve the channel name message was sent in
+    $inChannel = $_POST['channel_name'];
+    
+    //Get the first word sent in (should match trigger)
+    $firstWord = explode(" ",$inText);
+    $firstWord = $firstWord[0];
+    
+    $inText = substr($inText, strlen($firstWord)+1);
+    
+    if (isset($this->triggers->{$firstWord})) {
+      
+      //Retrieve the trigger
+      $trigger = $this->triggers->{$firstWord};
+      
+      //Make sure there is an attached action to the trigger word
+      if (sizeof($trigger->actions) > 0) {
+      
+        //Loop through and complete any actions attached to trigger
+        foreach ($trigger->actions as $action) {
+      
+          //Check for token, this is a requirement for security reasons
+          if (isset($this->token)) {
+            //Make sure we have a POSTed token and that the token matches the token we have supplied
+            if (isset($_POST['token']) && $_POST['token'] == $this->token) {
+              
+              $this->responseText = $action($inText, $inUser, $inChannel);
+              
+            } else {
+              $this->error = true;
+              array_push($this->errorMessages, "Mismatched tokens, please make sure the token you supplied matches the one setup with Slack webhook");
+            }
+            
+          } else {
+            $this->error = true;
+            array_push($this->errorMessages, "Please set a token with the constructor or using setToken function");
+          }
+        
+        } 
+        
+      } else {
+        $this->error = true;
+        array_push($this->errorMessages, "No action provided for the given trigger word: ".$firstWord);
+      }
+        
+      $ret = new stdClass;
+        
+      //If we are free from errors, return the response text we calculated
+      if (!$this->error) {
+        //Create a return for the Slack client
+        $ret->text = $this->responseText;
+      
+      //Otherwise we have an error, return all applicable messages
+      } else {
+        //Add error info
+        $ret->text = "`Error(s): ".implode(", ",$this->errorMessages)."`";
+      }
+      
+      //Convert to a JSON string
+      $ret = json_encode($ret);
+      
+      echo $ret;
+      
+    }
+  }
+}
+
+
+//class Trigger class
+class ShookerTrigger {
+  
+  private $triggerWord;
+  public $actions = array();
+  
+  //Create a trigger with given triggerword
+    function __construct($triggerWord) { 
+      $this->triggerWord = $triggerWord;
+    } 
+  
+  function addAction($fxn) {
+    array_push($this->actions, $fxn);
+  }
+}
+
+?>
\ No newline at end of file
diff --git a/public_html/vendor/spyc/spyc.php b/public_html/vendor/spyc/spyc.php
new file mode 100644
index 0000000000000000000000000000000000000000..2cf1bbc263db23da335fa1d74c8184493d5f8e5a
--- /dev/null
+++ b/public_html/vendor/spyc/spyc.php
@@ -0,0 +1,1161 @@
+<?php
+/**
+   * Spyc -- A Simple PHP YAML Class
+   * @version 0.6.2
+   * @author Vlad Andersen <vlad.andersen@gmail.com>
+   * @author Chris Wanstrath <chris@ozmm.org>
+   * @link https://github.com/mustangostang/spyc/
+   * @copyright Copyright 2005-2006 Chris Wanstrath, 2006-2011 Vlad Andersen
+   * @license http://www.opensource.org/licenses/mit-license.php MIT License
+   * @package Spyc
+   */
+
+if (!function_exists('spyc_load')) {
+  /**
+   * Parses YAML to array.
+   * @param string $string YAML string.
+   * @return array
+   */
+  function spyc_load ($string) {
+    return Spyc::YAMLLoadString($string);
+  }
+}
+
+if (!function_exists('spyc_load_file')) {
+  /**
+   * Parses YAML to array.
+   * @param string $file Path to YAML file.
+   * @return array
+   */
+  function spyc_load_file ($file) {
+    return Spyc::YAMLLoad($file);
+  }
+}
+
+if (!function_exists('spyc_dump')) {
+  /**
+   * Dumps array to YAML.
+   * @param array $data Array.
+   * @return string
+   */
+  function spyc_dump ($data) {
+    return Spyc::YAMLDump($data, false, false, true);
+  }
+}
+
+if (!class_exists('Spyc')) {
+
+/**
+   * The Simple PHP YAML Class.
+   *
+   * This class can be used to read a YAML file and convert its contents
+   * into a PHP array.  It currently supports a very limited subsection of
+   * the YAML spec.
+   *
+   * Usage:
+   * <code>
+   *   $Spyc  = new Spyc;
+   *   $array = $Spyc->load($file);
+   * </code>
+   * or:
+   * <code>
+   *   $array = Spyc::YAMLLoad($file);
+   * </code>
+   * or:
+   * <code>
+   *   $array = spyc_load_file($file);
+   * </code>
+   * @package Spyc
+   */
+class Spyc {
+
+  // SETTINGS
+
+  const REMPTY = "\0\0\0\0\0";
+
+  /**
+   * Setting this to true will force YAMLDump to enclose any string value in
+   * quotes.  False by default.
+   *
+   * @var bool
+   */
+  public $setting_dump_force_quotes = false;
+
+  /**
+   * Setting this to true will forse YAMLLoad to use syck_load function when
+   * possible. False by default.
+   * @var bool
+   */
+  public $setting_use_syck_is_possible = false;
+
+
+
+  /**#@+
+  * @access private
+  * @var mixed
+  */
+  private $_dumpIndent;
+  private $_dumpWordWrap;
+  private $_containsGroupAnchor = false;
+  private $_containsGroupAlias = false;
+  private $path;
+  private $result;
+  private $LiteralPlaceHolder = '___YAML_Literal_Block___';
+  private $SavedGroups = array();
+  private $indent;
+  /**
+   * Path modifier that should be applied after adding current element.
+   * @var array
+   */
+  private $delayedPath = array();
+
+  /**#@+
+  * @access public
+  * @var mixed
+  */
+  public $_nodeId;
+
+/**
+ * Load a valid YAML string to Spyc.
+ * @param string $input
+ * @return array
+ */
+  public function load ($input) {
+    return $this->_loadString($input);
+  }
+
+ /**
+ * Load a valid YAML file to Spyc.
+ * @param string $file
+ * @return array
+ */
+  public function loadFile ($file) {
+    return $this->_load($file);
+  }
+
+  /**
+     * Load YAML into a PHP array statically
+     *
+     * The load method, when supplied with a YAML stream (string or file),
+     * will do its best to convert YAML in a file into a PHP array.  Pretty
+     * simple.
+     *  Usage:
+     *  <code>
+     *   $array = Spyc::YAMLLoad('lucky.yaml');
+     *   print_r($array);
+     *  </code>
+     * @access public
+     * @return array
+     * @param string $input Path of YAML file or string containing YAML
+     */
+  public static function YAMLLoad($input) {
+    $Spyc = new Spyc;
+    return $Spyc->_load($input);
+  }
+
+  /**
+     * Load a string of YAML into a PHP array statically
+     *
+     * The load method, when supplied with a YAML string, will do its best
+     * to convert YAML in a string into a PHP array.  Pretty simple.
+     *
+     * Note: use this function if you don't want files from the file system
+     * loaded and processed as YAML.  This is of interest to people concerned
+     * about security whose input is from a string.
+     *
+     *  Usage:
+     *  <code>
+     *   $array = Spyc::YAMLLoadString("---\n0: hello world\n");
+     *   print_r($array);
+     *  </code>
+     * @access public
+     * @return array
+     * @param string $input String containing YAML
+     */
+  public static function YAMLLoadString($input) {
+    $Spyc = new Spyc;
+    return $Spyc->_loadString($input);
+  }
+
+  /**
+     * Dump YAML from PHP array statically
+     *
+     * The dump method, when supplied with an array, will do its best
+     * to convert the array into friendly YAML.  Pretty simple.  Feel free to
+     * save the returned string as nothing.yaml and pass it around.
+     *
+     * Oh, and you can decide how big the indent is and what the wordwrap
+     * for folding is.  Pretty cool -- just pass in 'false' for either if
+     * you want to use the default.
+     *
+     * Indent's default is 2 spaces, wordwrap's default is 40 characters.  And
+     * you can turn off wordwrap by passing in 0.
+     *
+     * @access public
+     * @return string
+     * @param array|\stdClass $array PHP array
+     * @param int $indent Pass in false to use the default, which is 2
+     * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40)
+     * @param bool $no_opening_dashes Do not start YAML file with "---\n"
+     */
+  public static function YAMLDump($array, $indent = false, $wordwrap = false, $no_opening_dashes = false) {
+    $spyc = new Spyc;
+    return $spyc->dump($array, $indent, $wordwrap, $no_opening_dashes);
+  }
+
+
+  /**
+     * Dump PHP array to YAML
+     *
+     * The dump method, when supplied with an array, will do its best
+     * to convert the array into friendly YAML.  Pretty simple.  Feel free to
+     * save the returned string as tasteful.yaml and pass it around.
+     *
+     * Oh, and you can decide how big the indent is and what the wordwrap
+     * for folding is.  Pretty cool -- just pass in 'false' for either if
+     * you want to use the default.
+     *
+     * Indent's default is 2 spaces, wordwrap's default is 40 characters.  And
+     * you can turn off wordwrap by passing in 0.
+     *
+     * @access public
+     * @return string
+     * @param array $array PHP array
+     * @param int $indent Pass in false to use the default, which is 2
+     * @param int $wordwrap Pass in 0 for no wordwrap, false for default (40)
+     */
+  public function dump($array,$indent = false,$wordwrap = false, $no_opening_dashes = false) {
+    // Dumps to some very clean YAML.  We'll have to add some more features
+    // and options soon.  And better support for folding.
+
+    // New features and options.
+    if ($indent === false or !is_numeric($indent)) {
+      $this->_dumpIndent = 2;
+    } else {
+      $this->_dumpIndent = $indent;
+    }
+
+    if ($wordwrap === false or !is_numeric($wordwrap)) {
+      $this->_dumpWordWrap = 40;
+    } else {
+      $this->_dumpWordWrap = $wordwrap;
+    }
+
+    // New YAML document
+    $string = "";
+    if (!$no_opening_dashes) $string = "---\n";
+
+    // Start at the base of the array and move through it.
+    if ($array) {
+      $array = (array)$array;
+      $previous_key = -1;
+      foreach ($array as $key => $value) {
+        if (!isset($first_key)) $first_key = $key;
+        $string .= $this->_yamlize($key,$value,0,$previous_key, $first_key, $array);
+        $previous_key = $key;
+      }
+    }
+    return $string;
+  }
+
+  /**
+     * Attempts to convert a key / value array item to YAML
+     * @access private
+     * @return string
+     * @param $key The name of the key
+     * @param $value The value of the item
+     * @param $indent The indent of the current node
+     */
+  private function _yamlize($key,$value,$indent, $previous_key = -1, $first_key = 0, $source_array = null) {
+    if(is_object($value)) $value = (array)$value;
+    if (is_array($value)) {
+      if (empty ($value))
+        return $this->_dumpNode($key, array(), $indent, $previous_key, $first_key, $source_array);
+      // It has children.  What to do?
+      // Make it the right kind of item
+      $string = $this->_dumpNode($key, self::REMPTY, $indent, $previous_key, $first_key, $source_array);
+      // Add the indent
+      $indent += $this->_dumpIndent;
+      // Yamlize the array
+      $string .= $this->_yamlizeArray($value,$indent);
+    } elseif (!is_array($value)) {
+      // It doesn't have children.  Yip.
+      $string = $this->_dumpNode($key, $value, $indent, $previous_key, $first_key, $source_array);
+    }
+    return $string;
+  }
+
+  /**
+     * Attempts to convert an array to YAML
+     * @access private
+     * @return string
+     * @param $array The array you want to convert
+     * @param $indent The indent of the current level
+     */
+  private function _yamlizeArray($array,$indent) {
+    if (is_array($array)) {
+      $string = '';
+      $previous_key = -1;
+      foreach ($array as $key => $value) {
+        if (!isset($first_key)) $first_key = $key;
+        $string .= $this->_yamlize($key, $value, $indent, $previous_key, $first_key, $array);
+        $previous_key = $key;
+      }
+      return $string;
+    } else {
+      return false;
+    }
+  }
+
+  /**
+     * Returns YAML from a key and a value
+     * @access private
+     * @return string
+     * @param $key The name of the key
+     * @param $value The value of the item
+     * @param $indent The indent of the current node
+     */
+  private function _dumpNode($key, $value, $indent, $previous_key = -1, $first_key = 0, $source_array = null) {
+    // do some folding here, for blocks
+    if (is_string ($value) && ((strpos($value,"\n") !== false || strpos($value,": ") !== false || strpos($value,"- ") !== false ||
+      strpos($value,"*") !== false || strpos($value,"#") !== false || strpos($value,"<") !== false || strpos($value,">") !== false || strpos ($value, '%') !== false || strpos ($value, '  ') !== false ||
+      strpos($value,"[") !== false || strpos($value,"]") !== false || strpos($value,"{") !== false || strpos($value,"}") !== false) || strpos($value,"&") !== false || strpos($value, "'") !== false || strpos($value, "!") === 0 ||
+      substr ($value, -1, 1) == ':')
+    ) {
+      $value = $this->_doLiteralBlock($value,$indent);
+    } else {
+      $value  = $this->_doFolding($value,$indent);
+    }
+
+    if ($value === array()) $value = '[ ]';
+    if ($value === "") $value = '""';
+    if (self::isTranslationWord($value)) {
+      $value = $this->_doLiteralBlock($value, $indent);
+    }
+    if (trim ($value) != $value)
+       $value = $this->_doLiteralBlock($value,$indent);
+
+    if (is_bool($value)) {
+       $value = $value ? "true" : "false";
+    }
+
+    if ($value === null) $value = 'null';
+    if ($value === "'" . self::REMPTY . "'") $value = null;
+
+    $spaces = str_repeat(' ',$indent);
+
+    //if (is_int($key) && $key - 1 == $previous_key && $first_key===0) {
+    if (is_array ($source_array) && array_keys($source_array) === range(0, count($source_array) - 1)) {
+      // It's a sequence
+      $string = $spaces.'- '.$value."\n";
+    } else {
+      // if ($first_key===0)  throw new Exception('Keys are all screwy.  The first one was zero, now it\'s "'. $key .'"');
+      // It's mapped
+      if (strpos($key, ":") !== false || strpos($key, "#") !== false) { $key = '"' . $key . '"'; }
+      $string = rtrim ($spaces.$key.': '.$value)."\n";
+    }
+    return $string;
+  }
+
+  /**
+     * Creates a literal block for dumping
+     * @access private
+     * @return string
+     * @param $value
+     * @param $indent int The value of the indent
+     */
+  private function _doLiteralBlock($value,$indent) {
+    if ($value === "\n") return '\n';
+    if (strpos($value, "\n") === false && strpos($value, "'") === false) {
+      return sprintf ("'%s'", $value);
+    }
+    if (strpos($value, "\n") === false && strpos($value, '"') === false) {
+      return sprintf ('"%s"', $value);
+    }
+    $exploded = explode("\n",$value);
+    $newValue = '|';
+    if (isset($exploded[0]) && ($exploded[0] == "|" || $exploded[0] == "|-" || $exploded[0] == ">")) {
+        $newValue = $exploded[0];
+        unset($exploded[0]);
+    }
+    $indent += $this->_dumpIndent;
+    $spaces   = str_repeat(' ',$indent);
+    foreach ($exploded as $line) {
+      $line = trim($line);
+      if (strpos($line, '"') === 0 && strrpos($line, '"') == (strlen($line)-1) || strpos($line, "'") === 0 && strrpos($line, "'") == (strlen($line)-1)) {
+        $line = substr($line, 1, -1);
+      }
+      $newValue .= "\n" . $spaces . ($line);
+    }
+    return $newValue;
+  }
+
+  /**
+     * Folds a string of text, if necessary
+     * @access private
+     * @return string
+     * @param $value The string you wish to fold
+     */
+  private function _doFolding($value,$indent) {
+    // Don't do anything if wordwrap is set to 0
+
+    if ($this->_dumpWordWrap !== 0 && is_string ($value) && strlen($value) > $this->_dumpWordWrap) {
+      $indent += $this->_dumpIndent;
+      $indent = str_repeat(' ',$indent);
+      $wrapped = wordwrap($value,$this->_dumpWordWrap,"\n$indent");
+      $value   = ">\n".$indent.$wrapped;
+    } else {
+      if ($this->setting_dump_force_quotes && is_string ($value) && $value !== self::REMPTY)
+        $value = '"' . $value . '"';
+      if (is_numeric($value) && is_string($value))
+        $value = '"' . $value . '"';
+    }
+
+
+    return $value;
+  }
+
+  private function isTrueWord($value) {
+    $words = self::getTranslations(array('true', 'on', 'yes', 'y'));
+    return in_array($value, $words, true);
+  }
+
+  private function isFalseWord($value) {
+    $words = self::getTranslations(array('false', 'off', 'no', 'n'));
+    return in_array($value, $words, true);
+  }
+
+  private function isNullWord($value) {
+    $words = self::getTranslations(array('null', '~'));
+    return in_array($value, $words, true);
+  }
+
+  private function isTranslationWord($value) {
+    return (
+      self::isTrueWord($value)  ||
+      self::isFalseWord($value) ||
+      self::isNullWord($value)
+    );
+  }
+
+  /**
+     * Coerce a string into a native type
+     * Reference: http://yaml.org/type/bool.html
+     * TODO: Use only words from the YAML spec.
+     * @access private
+     * @param $value The value to coerce
+     */
+  private function coerceValue(&$value) {
+    if (self::isTrueWord($value)) {
+      $value = true;
+    } else if (self::isFalseWord($value)) {
+      $value = false;
+    } else if (self::isNullWord($value)) {
+      $value = null;
+    }
+  }
+
+  /**
+     * Given a set of words, perform the appropriate translations on them to
+     * match the YAML 1.1 specification for type coercing.
+     * @param $words The words to translate
+     * @access private
+     */
+  private static function getTranslations(array $words) {
+    $result = array();
+    foreach ($words as $i) {
+      $result = array_merge($result, array(ucfirst($i), strtoupper($i), strtolower($i)));
+    }
+    return $result;
+  }
+
+// LOADING FUNCTIONS
+
+  private function _load($input) {
+    $Source = $this->loadFromSource($input);
+    return $this->loadWithSource($Source);
+  }
+
+  private function _loadString($input) {
+    $Source = $this->loadFromString($input);
+    return $this->loadWithSource($Source);
+  }
+
+  private function loadWithSource($Source) {
+    if (empty ($Source)) return array();
+    if ($this->setting_use_syck_is_possible && function_exists ('syck_load')) {
+      $array = syck_load (implode ("\n", $Source));
+      return is_array($array) ? $array : array();
+    }
+
+    $this->path = array();
+    $this->result = array();
+
+    $cnt = count($Source);
+    for ($i = 0; $i < $cnt; $i++) {
+      $line = $Source[$i];
+
+      $this->indent = strlen($line) - strlen(ltrim($line));
+      $tempPath = $this->getParentPathByIndent($this->indent);
+      $line = self::stripIndent($line, $this->indent);
+      if (self::isComment($line)) continue;
+      if (self::isEmpty($line)) continue;
+      $this->path = $tempPath;
+
+      $literalBlockStyle = self::startsLiteralBlock($line);
+      if ($literalBlockStyle) {
+        $line = rtrim ($line, $literalBlockStyle . " \n");
+        $literalBlock = '';
+        $line .= ' '.$this->LiteralPlaceHolder;
+        $literal_block_indent = strlen($Source[$i+1]) - strlen(ltrim($Source[$i+1]));
+        while (++$i < $cnt && $this->literalBlockContinues($Source[$i], $this->indent)) {
+          $literalBlock = $this->addLiteralLine($literalBlock, $Source[$i], $literalBlockStyle, $literal_block_indent);
+        }
+        $i--;
+      }
+
+      // Strip out comments
+      if (strpos ($line, '#')) {
+          $line = preg_replace('/\s*#([^"\']+)$/','',$line);
+      }
+
+      while (++$i < $cnt && self::greedilyNeedNextLine($line)) {
+        $line = rtrim ($line, " \n\t\r") . ' ' . ltrim ($Source[$i], " \t");
+      }
+      $i--;
+
+      $lineArray = $this->_parseLine($line);
+
+      if ($literalBlockStyle)
+        $lineArray = $this->revertLiteralPlaceHolder ($lineArray, $literalBlock);
+
+      $this->addArray($lineArray, $this->indent);
+
+      foreach ($this->delayedPath as $indent => $delayedPath)
+        $this->path[$indent] = $delayedPath;
+
+      $this->delayedPath = array();
+
+    }
+    return $this->result;
+  }
+
+  private function loadFromSource ($input) {
+    if (!empty($input) && strpos($input, "\n") === false && file_exists($input))
+      $input = file_get_contents($input);
+
+    return $this->loadFromString($input);
+  }
+
+  private function loadFromString ($input) {
+    $lines = explode("\n",$input);
+    foreach ($lines as $k => $_) {
+      $lines[$k] = rtrim ($_, "\r");
+    }
+    return $lines;
+  }
+
+  /**
+     * Parses YAML code and returns an array for a node
+     * @access private
+     * @return array
+     * @param string $line A line from the YAML file
+     */
+  private function _parseLine($line) {
+    if (!$line) return array();
+    $line = trim($line);
+    if (!$line) return array();
+
+    $array = array();
+
+    $group = $this->nodeContainsGroup($line);
+    if ($group) {
+      $this->addGroup($line, $group);
+      $line = $this->stripGroup ($line, $group);
+    }
+
+    if ($this->startsMappedSequence($line))
+      return $this->returnMappedSequence($line);
+
+    if ($this->startsMappedValue($line))
+      return $this->returnMappedValue($line);
+
+    if ($this->isArrayElement($line))
+     return $this->returnArrayElement($line);
+
+    if ($this->isPlainArray($line))
+     return $this->returnPlainArray($line);
+
+
+    return $this->returnKeyValuePair($line);
+
+  }
+
+  /**
+     * Finds the type of the passed value, returns the value as the new type.
+     * @access private
+     * @param string $value
+     * @return mixed
+     */
+  private function _toType($value) {
+    if ($value === '') return "";
+    $first_character = $value[0];
+    $last_character = substr($value, -1, 1);
+
+    $is_quoted = false;
+    do {
+      if (!$value) break;
+      if ($first_character != '"' && $first_character != "'") break;
+      if ($last_character != '"' && $last_character != "'") break;
+      $is_quoted = true;
+    } while (0);
+
+    if ($is_quoted) {
+      $value = str_replace('\n', "\n", $value);
+      if ($first_character == "'")
+        return strtr(substr ($value, 1, -1), array ('\'\'' => '\'', '\\\''=> '\''));
+      return strtr(substr ($value, 1, -1), array ('\\"' => '"', '\\\''=> '\''));
+    }
+
+    if (strpos($value, ' #') !== false && !$is_quoted)
+      $value = preg_replace('/\s+#(.+)$/','',$value);
+
+    if ($first_character == '[' && $last_character == ']') {
+      // Take out strings sequences and mappings
+      $innerValue = trim(substr ($value, 1, -1));
+      if ($innerValue === '') return array();
+      $explode = $this->_inlineEscape($innerValue);
+      // Propagate value array
+      $value  = array();
+      foreach ($explode as $v) {
+        $value[] = $this->_toType($v);
+      }
+      return $value;
+    }
+
+    if (strpos($value,': ')!==false && $first_character != '{') {
+      $array = explode(': ',$value);
+      $key   = trim($array[0]);
+      array_shift($array);
+      $value = trim(implode(': ',$array));
+      $value = $this->_toType($value);
+      return array($key => $value);
+    }
+
+    if ($first_character == '{' && $last_character == '}') {
+      $innerValue = trim(substr ($value, 1, -1));
+      if ($innerValue === '') return array();
+      // Inline Mapping
+      // Take out strings sequences and mappings
+      $explode = $this->_inlineEscape($innerValue);
+      // Propagate value array
+      $array = array();
+      foreach ($explode as $v) {
+        $SubArr = $this->_toType($v);
+        if (empty($SubArr)) continue;
+        if (is_array ($SubArr)) {
+          $array[key($SubArr)] = $SubArr[key($SubArr)]; continue;
+        }
+        $array[] = $SubArr;
+      }
+      return $array;
+    }
+
+    if ($value == 'null' || $value == 'NULL' || $value == 'Null' || $value == '' || $value == '~') {
+      return null;
+    }
+
+    if ( is_numeric($value) && preg_match ('/^(-|)[1-9]+[0-9]*$/', $value) ){
+      $intvalue = (int)$value;
+      if ($intvalue != PHP_INT_MAX && $intvalue != ~PHP_INT_MAX)
+        $value = $intvalue;
+      return $value;
+    }
+
+    if ( is_string($value) && preg_match('/^0[xX][0-9a-fA-F]+$/', $value)) {
+      // Hexadecimal value.
+      return hexdec($value);
+    }
+
+    $this->coerceValue($value);
+
+    if (is_numeric($value)) {
+      if ($value === '0') return 0;
+      if (rtrim ($value, 0) === $value)
+        $value = (float)$value;
+      return $value;
+    }
+
+    return $value;
+  }
+
+  /**
+     * Used in inlines to check for more inlines or quoted strings
+     * @access private
+     * @return array
+     */
+  private function _inlineEscape($inline) {
+    // There's gotta be a cleaner way to do this...
+    // While pure sequences seem to be nesting just fine,
+    // pure mappings and mappings with sequences inside can't go very
+    // deep.  This needs to be fixed.
+
+    $seqs = array();
+    $maps = array();
+    $saved_strings = array();
+    $saved_empties = array();
+
+    // Check for empty strings
+    $regex = '/("")|(\'\')/';
+    if (preg_match_all($regex,$inline,$strings)) {
+      $saved_empties = $strings[0];
+      $inline  = preg_replace($regex,'YAMLEmpty',$inline);
+    }
+    unset($regex);
+
+    // Check for strings
+    $regex = '/(?:(")|(?:\'))((?(1)[^"]+|[^\']+))(?(1)"|\')/';
+    if (preg_match_all($regex,$inline,$strings)) {
+      $saved_strings = $strings[0];
+      $inline  = preg_replace($regex,'YAMLString',$inline);
+    }
+    unset($regex);
+
+    // echo $inline;
+
+    $i = 0;
+    do {
+
+    // Check for sequences
+    while (preg_match('/\[([^{}\[\]]+)\]/U',$inline,$matchseqs)) {
+      $seqs[] = $matchseqs[0];
+      $inline = preg_replace('/\[([^{}\[\]]+)\]/U', ('YAMLSeq' . (count($seqs) - 1) . 's'), $inline, 1);
+    }
+
+    // Check for mappings
+    while (preg_match('/{([^\[\]{}]+)}/U',$inline,$matchmaps)) {
+      $maps[] = $matchmaps[0];
+      $inline = preg_replace('/{([^\[\]{}]+)}/U', ('YAMLMap' . (count($maps) - 1) . 's'), $inline, 1);
+    }
+
+    if ($i++ >= 10) break;
+
+    } while (strpos ($inline, '[') !== false || strpos ($inline, '{') !== false);
+
+    $explode = explode(',',$inline);
+    $explode = array_map('trim', $explode);
+    $stringi = 0; $i = 0;
+
+    while (1) {
+
+    // Re-add the sequences
+    if (!empty($seqs)) {
+      foreach ($explode as $key => $value) {
+        if (strpos($value,'YAMLSeq') !== false) {
+          foreach ($seqs as $seqk => $seq) {
+            $explode[$key] = str_replace(('YAMLSeq'.$seqk.'s'),$seq,$value);
+            $value = $explode[$key];
+          }
+        }
+      }
+    }
+
+    // Re-add the mappings
+    if (!empty($maps)) {
+      foreach ($explode as $key => $value) {
+        if (strpos($value,'YAMLMap') !== false) {
+          foreach ($maps as $mapk => $map) {
+            $explode[$key] = str_replace(('YAMLMap'.$mapk.'s'), $map, $value);
+            $value = $explode[$key];
+          }
+        }
+      }
+    }
+
+
+    // Re-add the strings
+    if (!empty($saved_strings)) {
+      foreach ($explode as $key => $value) {
+        while (strpos($value,'YAMLString') !== false) {
+          $explode[$key] = preg_replace('/YAMLString/',$saved_strings[$stringi],$value, 1);
+          unset($saved_strings[$stringi]);
+          ++$stringi;
+          $value = $explode[$key];
+        }
+      }
+    }
+
+
+    // Re-add the empties
+    if (!empty($saved_empties)) {
+      foreach ($explode as $key => $value) {
+        while (strpos($value,'YAMLEmpty') !== false) {
+          $explode[$key] = preg_replace('/YAMLEmpty/', '', $value, 1);
+          $value = $explode[$key];
+        }
+      }
+    }
+
+    $finished = true;
+    foreach ($explode as $key => $value) {
+      if (strpos($value,'YAMLSeq') !== false) {
+        $finished = false; break;
+      }
+      if (strpos($value,'YAMLMap') !== false) {
+        $finished = false; break;
+      }
+      if (strpos($value,'YAMLString') !== false) {
+        $finished = false; break;
+      }
+      if (strpos($value,'YAMLEmpty') !== false) {
+        $finished = false; break;
+      }
+    }
+    if ($finished) break;
+
+    $i++;
+    if ($i > 10)
+      break; // Prevent infinite loops.
+    }
+
+
+    return $explode;
+  }
+
+  private function literalBlockContinues ($line, $lineIndent) {
+    if (!trim($line)) return true;
+    if (strlen($line) - strlen(ltrim($line)) > $lineIndent) return true;
+    return false;
+  }
+
+  private function referenceContentsByAlias ($alias) {
+    do {
+      if (!isset($this->SavedGroups[$alias])) { echo "Bad group name: $alias."; break; }
+      $groupPath = $this->SavedGroups[$alias];
+      $value = $this->result;
+      foreach ($groupPath as $k) {
+        $value = $value[$k];
+      }
+    } while (false);
+    return $value;
+  }
+
+  private function addArrayInline ($array, $indent) {
+      $CommonGroupPath = $this->path;
+      if (empty ($array)) return false;
+
+      foreach ($array as $k => $_) {
+        $this->addArray(array($k => $_), $indent);
+        $this->path = $CommonGroupPath;
+      }
+      return true;
+  }
+
+  private function addArray ($incoming_data, $incoming_indent) {
+
+   // print_r ($incoming_data);
+
+    if (count ($incoming_data) > 1)
+      return $this->addArrayInline ($incoming_data, $incoming_indent);
+
+    $key = key ($incoming_data);
+    $value = isset($incoming_data[$key]) ? $incoming_data[$key] : null;
+    if ($key === '__!YAMLZero') $key = '0';
+
+    if ($incoming_indent == 0 && !$this->_containsGroupAlias && !$this->_containsGroupAnchor) { // Shortcut for root-level values.
+      if ($key || $key === '' || $key === '0') {
+        $this->result[$key] = $value;
+      } else {
+        $this->result[] = $value; end ($this->result); $key = key ($this->result);
+      }
+      $this->path[$incoming_indent] = $key;
+      return;
+    }
+
+
+
+    $history = array();
+    // Unfolding inner array tree.
+    $history[] = $_arr = $this->result;
+    foreach ($this->path as $k) {
+      $history[] = $_arr = $_arr[$k];
+    }
+
+    if ($this->_containsGroupAlias) {
+      $value = $this->referenceContentsByAlias($this->_containsGroupAlias);
+      $this->_containsGroupAlias = false;
+    }
+
+
+    // Adding string or numeric key to the innermost level or $this->arr.
+    if (is_string($key) && $key == '<<') {
+      if (!is_array ($_arr)) { $_arr = array (); }
+
+      $_arr = array_merge ($_arr, $value);
+    } else if ($key || $key === '' || $key === '0') {
+      if (!is_array ($_arr))
+        $_arr = array ($key=>$value);
+      else
+        $_arr[$key] = $value;
+    } else {
+      if (!is_array ($_arr)) { $_arr = array ($value); $key = 0; }
+      else { $_arr[] = $value; end ($_arr); $key = key ($_arr); }
+    }
+
+    $reverse_path = array_reverse($this->path);
+    $reverse_history = array_reverse ($history);
+    $reverse_history[0] = $_arr;
+    $cnt = count($reverse_history) - 1;
+    for ($i = 0; $i < $cnt; $i++) {
+      $reverse_history[$i+1][$reverse_path[$i]] = $reverse_history[$i];
+    }
+    $this->result = $reverse_history[$cnt];
+
+    $this->path[$incoming_indent] = $key;
+
+    if ($this->_containsGroupAnchor) {
+      $this->SavedGroups[$this->_containsGroupAnchor] = $this->path;
+      if (is_array ($value)) {
+        $k = key ($value);
+        if (!is_int ($k)) {
+          $this->SavedGroups[$this->_containsGroupAnchor][$incoming_indent + 2] = $k;
+        }
+      }
+      $this->_containsGroupAnchor = false;
+    }
+
+  }
+
+  private static function startsLiteralBlock ($line) {
+    $lastChar = substr (trim($line), -1);
+    if ($lastChar != '>' && $lastChar != '|') return false;
+    if ($lastChar == '|') return $lastChar;
+    // HTML tags should not be counted as literal blocks.
+    if (preg_match ('#<.*?>$#', $line)) return false;
+    return $lastChar;
+  }
+
+  private static function greedilyNeedNextLine($line) {
+    $line = trim ($line);
+    if (!strlen($line)) return false;
+    if (substr ($line, -1, 1) == ']') return false;
+    if ($line[0] == '[') return true;
+    if (preg_match ('#^[^:]+?:\s*\[#', $line)) return true;
+    return false;
+  }
+
+  private function addLiteralLine ($literalBlock, $line, $literalBlockStyle, $indent = -1) {
+    $line = self::stripIndent($line, $indent);
+    if ($literalBlockStyle !== '|') {
+        $line = self::stripIndent($line);
+    }
+    $line = rtrim ($line, "\r\n\t ") . "\n";
+    if ($literalBlockStyle == '|') {
+      return $literalBlock . $line;
+    }
+    if (strlen($line) == 0)
+      return rtrim($literalBlock, ' ') . "\n";
+    if ($line == "\n" && $literalBlockStyle == '>') {
+      return rtrim ($literalBlock, " \t") . "\n";
+    }
+    if ($line != "\n")
+      $line = trim ($line, "\r\n ") . " ";
+    return $literalBlock . $line;
+  }
+
+   function revertLiteralPlaceHolder ($lineArray, $literalBlock) {
+     foreach ($lineArray as $k => $_) {
+      if (is_array($_))
+        $lineArray[$k] = $this->revertLiteralPlaceHolder ($_, $literalBlock);
+      else if (substr($_, -1 * strlen ($this->LiteralPlaceHolder)) == $this->LiteralPlaceHolder)
+	       $lineArray[$k] = rtrim ($literalBlock, " \r\n");
+     }
+     return $lineArray;
+   }
+
+  private static function stripIndent ($line, $indent = -1) {
+    if ($indent == -1) $indent = strlen($line) - strlen(ltrim($line));
+    return substr ($line, $indent);
+  }
+
+  private function getParentPathByIndent ($indent) {
+    if ($indent == 0) return array();
+    $linePath = $this->path;
+    do {
+      end($linePath); $lastIndentInParentPath = key($linePath);
+      if ($indent <= $lastIndentInParentPath) array_pop ($linePath);
+    } while ($indent <= $lastIndentInParentPath);
+    return $linePath;
+  }
+
+
+  private function clearBiggerPathValues ($indent) {
+
+
+    if ($indent == 0) $this->path = array();
+    if (empty ($this->path)) return true;
+
+    foreach ($this->path as $k => $_) {
+      if ($k > $indent) unset ($this->path[$k]);
+    }
+
+    return true;
+  }
+
+
+  private static function isComment ($line) {
+    if (!$line) return false;
+    if ($line[0] == '#') return true;
+    if (trim($line, " \r\n\t") == '---') return true;
+    return false;
+  }
+
+  private static function isEmpty ($line) {
+    return (trim ($line) === '');
+  }
+
+
+  private function isArrayElement ($line) {
+    if (!$line || !is_scalar($line)) return false;
+    if (substr($line, 0, 2) != '- ') return false;
+    if (strlen ($line) > 3)
+      if (substr($line,0,3) == '---') return false;
+
+    return true;
+  }
+
+  private function isHashElement ($line) {
+    return strpos($line, ':');
+  }
+
+  private function isLiteral ($line) {
+    if ($this->isArrayElement($line)) return false;
+    if ($this->isHashElement($line)) return false;
+    return true;
+  }
+
+
+  private static function unquote ($value) {
+    if (!$value) return $value;
+    if (!is_string($value)) return $value;
+    if ($value[0] == '\'') return trim ($value, '\'');
+    if ($value[0] == '"') return trim ($value, '"');
+    return $value;
+  }
+
+  private function startsMappedSequence ($line) {
+    return (substr($line, 0, 2) == '- ' && substr ($line, -1, 1) == ':');
+  }
+
+  private function returnMappedSequence ($line) {
+    $array = array();
+    $key         = self::unquote(trim(substr($line,1,-1)));
+    $array[$key] = array();
+    $this->delayedPath = array(strpos ($line, $key) + $this->indent => $key);
+    return array($array);
+  }
+
+  private function checkKeysInValue($value) {
+    if (strchr('[{"\'', $value[0]) === false) {
+      if (strchr($value, ': ') !== false) {
+          throw new Exception('Too many keys: '.$value);
+      }
+    }
+  }
+
+  private function returnMappedValue ($line) {
+    $this->checkKeysInValue($line);
+    $array = array();
+    $key         = self::unquote (trim(substr($line,0,-1)));
+    $array[$key] = '';
+    return $array;
+  }
+
+  private function startsMappedValue ($line) {
+    return (substr ($line, -1, 1) == ':');
+  }
+
+  private function isPlainArray ($line) {
+    return ($line[0] == '[' && substr ($line, -1, 1) == ']');
+  }
+
+  private function returnPlainArray ($line) {
+    return $this->_toType($line);
+  }
+
+  private function returnKeyValuePair ($line) {
+    $array = array();
+    $key = '';
+    if (strpos ($line, ': ')) {
+      // It's a key/value pair most likely
+      // If the key is in double quotes pull it out
+      if (($line[0] == '"' || $line[0] == "'") && preg_match('/^(["\'](.*)["\'](\s)*:)/',$line,$matches)) {
+        $value = trim(str_replace($matches[1],'',$line));
+        $key   = $matches[2];
+      } else {
+        // Do some guesswork as to the key and the value
+        $explode = explode(': ', $line);
+        $key     = trim(array_shift($explode));
+        $value   = trim(implode(': ', $explode));
+        $this->checkKeysInValue($value);
+      }
+      // Set the type of the value.  Int, string, etc
+      $value = $this->_toType($value);
+      if ($key === '0') $key = '__!YAMLZero';
+      $array[$key] = $value;
+    } else {
+      $array = array ($line);
+    }
+    return $array;
+
+  }
+
+
+  private function returnArrayElement ($line) {
+     if (strlen($line) <= 1) return array(array()); // Weird %)
+     $array = array();
+     $value   = trim(substr($line,1));
+     $value   = $this->_toType($value);
+     if ($this->isArrayElement($value)) {
+       $value = $this->returnArrayElement($value);
+     }
+     $array[] = $value;
+     return $array;
+  }
+
+
+  private function nodeContainsGroup ($line) {
+    $symbolsForReference = 'A-z0-9_\-';
+    if (strpos($line, '&') === false && strpos($line, '*') === false) return false; // Please die fast ;-)
+    if ($line[0] == '&' && preg_match('/^(&['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1];
+    if ($line[0] == '*' && preg_match('/^(\*['.$symbolsForReference.']+)/', $line, $matches)) return $matches[1];
+    if (preg_match('/(&['.$symbolsForReference.']+)$/', $line, $matches)) return $matches[1];
+    if (preg_match('/(\*['.$symbolsForReference.']+$)/', $line, $matches)) return $matches[1];
+    if (preg_match ('#^\s*<<\s*:\s*(\*[^\s]+).*$#', $line, $matches)) return $matches[1];
+    return false;
+
+  }
+
+  private function addGroup ($line, $group) {
+    if ($group[0] == '&') $this->_containsGroupAnchor = substr ($group, 1);
+    if ($group[0] == '*') $this->_containsGroupAlias = substr ($group, 1);
+    //print_r ($this->path);
+  }
+
+  private function stripGroup ($line, $group) {
+    $line = trim(str_replace($group, '', $line));
+    return $line;
+  }
+}
+}
+
+// Enable use of Spyc from command line
+// The syntax is the following: php Spyc.php spyc.yaml
+
+do {
+  if (PHP_SAPI != 'cli') break;
+  if (empty ($_SERVER['argc']) || $_SERVER['argc'] < 2) break;
+  if (empty ($_SERVER['PHP_SELF']) || FALSE === strpos ($_SERVER['PHP_SELF'], 'Spyc.php') ) break;
+  $file = $argv[1];
+  echo json_encode (spyc_load_file ($file));
+} while (0);
\ No newline at end of file