gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] r33405 - in eclectic: . gplmt-ui gplmt-ui/Zabbix-2.0 gplmt-


From: gnunet
Subject: [GNUnet-SVN] r33405 - in eclectic: . gplmt-ui gplmt-ui/Zabbix-2.0 gplmt-ui/Zabbix-2.2
Date: Mon, 26 May 2014 21:45:47 +0200

Author: otarabai
Date: 2014-05-26 21:45:47 +0200 (Mon, 26 May 2014)
New Revision: 33405

Added:
   eclectic/gplmt-ui/Zabbix-2.0/
   eclectic/gplmt-ui/Zabbix-2.0/README
   eclectic/gplmt-ui/Zabbix-2.0/data.sql
   eclectic/gplmt-ui/Zabbix-2.0/diff
   eclectic/gplmt-ui/Zabbix-2.0/schema.sql
   eclectic/gplmt-ui/Zabbix-2.2/
   eclectic/gplmt-ui/Zabbix-2.2/README
   eclectic/gplmt-ui/Zabbix-2.2/data.sql
   eclectic/gplmt-ui/Zabbix-2.2/patch.diff
   eclectic/gplmt-ui/Zabbix-2.2/schema.sql
Removed:
   eclectic/gplmt-ui/README
   eclectic/gplmt-ui/data.sql
   eclectic/gplmt-ui/diff
   eclectic/gplmt-ui/schema.sql
Modified:
   eclectic/installation-guide.pdf
   eclectic/installation-guide.tex
Log:
GPLMT UI for Zabbix 2.2


Deleted: eclectic/gplmt-ui/README
===================================================================
--- eclectic/gplmt-ui/README    2014-05-26 19:38:06 UTC (rev 33404)
+++ eclectic/gplmt-ui/README    2014-05-26 19:45:47 UTC (rev 33405)
@@ -1,8 +0,0 @@
-GPLMT Web UI
-============
-
-This is a diff which has to be applied against Zabbix version 2.0.4
-
-schema.sql and data.sql to be applied to Zabbix mysql database
-
-See ../installation-guide.pdf for more details

Added: eclectic/gplmt-ui/Zabbix-2.0/README
===================================================================
--- eclectic/gplmt-ui/Zabbix-2.0/README                         (rev 0)
+++ eclectic/gplmt-ui/Zabbix-2.0/README 2014-05-26 19:45:47 UTC (rev 33405)
@@ -0,0 +1,8 @@
+GPLMT Web UI
+============
+
+This is a diff which has to be applied against Zabbix version 2.0.4
+
+schema.sql and data.sql to be applied to Zabbix mysql database
+
+See ../installation-guide.pdf for more details

Added: eclectic/gplmt-ui/Zabbix-2.0/data.sql
===================================================================
--- eclectic/gplmt-ui/Zabbix-2.0/data.sql                               (rev 0)
+++ eclectic/gplmt-ui/Zabbix-2.0/data.sql       2014-05-26 19:45:47 UTC (rev 
33405)
@@ -0,0 +1,54 @@
+-- phpMyAdmin SQL Dump
+-- version 3.4.11.1deb2
+-- http://www.phpmyadmin.net
+--
+-- Host: localhost
+-- Generation Time: Sep 26, 2013 at 04:40 PM
+-- Server version: 5.5.31
+-- PHP Version: 5.4.4-14+deb7u4
+
+SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
+SET time_zone = "+00:00";
+
+
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
+/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
+/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
+/*!40101 SET NAMES utf8 */;
+
+--
+-- Database: `zabbix`
+--
+
+--
+-- Dumping data for table `exp_config`
+--
+
+INSERT INTO `exp_config` (`configid`, `section`, `name`, `label`, 
`description`, `type`, `default_value`, `user_editable`) VALUES
+(1, 'ssh', 'ssh_username', 'SSH username', 'Username for SSH access', 'text', 
'', 1),
+(2, 'ssh', 'ssh_password', 'SSH password', 'Password for SSH access or 
password for the SSH keyfile', 'password', '', 1),
+(3, 'ssh', 'ssh_keyfile', 'SSH keyfile', 'SSH key for login', 'file', '', 1),
+(16, 'gplmt', 'notification', 'Notification', 'Which notification mechanism to 
use: simple, result', 'text', 'result', 0),
+(17, 'gplmt', 'max_parallelism', 'Max Parallelism', 'Number of parallel 
workers, use 0 for unlimited', 'integer', '10', 0),
+(18, 'planetlab', 'slice', 'Planetlab Slice', 'Name of your PlanetLab Slice', 
'text', '', 1),
+(20, 'planetlab', 'api_url', 'PLC/PLE', 'Use PlanetLab Central or PlanetLab 
Europe', 'enum', 'https://www.planet-lab.eu/PLCAPI/', 1),
+(21, 'planetlab', 'username', 'PlanetLab API username', 'Your login to the 
planetlab website\r\nto access the planetlab API', 'text', '', 1),
+(22, 'planetlab', 'password', 'PlanetLab API password', 'Your password for the 
planetlab\r\nwebsite to access the planetlab API', 'password', '', 1),
+(25, 'ssh', 'ssh_transfer', 'SSH Transfer', 'Protocol for put get operations: 
scp, sftp', 'text', 'scp', 0),
+(26, 'ssh', 'ssh_use_known_hosts', 'SSH: Use Known Hosts', 'Use system''s SSH 
"known hosts" file', 'boolean', 'yes', 0),
+(27, 'ssh', 'add_unkown_hostkeys', 'SSH: Add Unknown Hostkeys', 'Add node 
hostkeys automatically', 'boolean', 'yes', 0),
+(28, 'gplmt', 'userdir', 'User Directory', 'User specific directory for 
put/get operations', 'text', '', 0);
+
+INSERT INTO `zabbix`.`exp_config` (`configid`, `section`, `name`, `label`, 
`description`, `type`, `default_value`, `user_editable`) VALUES (NULL, 
'planetlab', 'pl_keyfile', 'Planetlab keyfile', 'Private key file for 
connecting to planetlab nodes', 'file', '', '1'), (NULL, 'planetlab', 
'pl_keyfile_password', 'Planetlab keyfile password', 'Password used to unlock 
private key file (if needed)', 'password', '', '1');
+
+--
+-- Dumping data for table `exp_configenum`
+--
+
+INSERT INTO `exp_configenum` (`id`, `configid`, `label`, `value`) VALUES
+(1, 20, 'Planetlab Central', 'https://www.planet-lab.org/PLCAPI/'),
+(2, 20, 'Planetlab Europe', 'https://www.planet-lab.eu/PLCAPI/');
+
+/*!40101 SET address@hidden */;
+/*!40101 SET address@hidden */;
+/*!40101 SET address@hidden */;

Added: eclectic/gplmt-ui/Zabbix-2.0/diff
===================================================================
--- eclectic/gplmt-ui/Zabbix-2.0/diff                           (rev 0)
+++ eclectic/gplmt-ui/Zabbix-2.0/diff   2014-05-26 19:45:47 UTC (rev 33405)
@@ -0,0 +1,3058 @@
+diff --git conf.php conf.php
+new file mode 100644
+index 0000000..c88d8a6
+--- /dev/null
++++ conf.php
+@@ -0,0 +1,31 @@
++<?php
++
++require_once dirname(__FILE__).'/include/config.inc.php';
++require_once dirname(__FILE__).'/include/experiments/inc.php';
++
++$page['title'] = _('User Configuration');
++$page['file'] = 'conf.php';
++$page['hist_arg'] = array('confid');
++
++require_once dirname(__FILE__).'/include/page_header.php';
++
++/*
++ * Actions
++ */
++if(isset($_REQUEST['update']))
++{
++    //print_r($_REQUEST);
++    expconfig_update($_REQUEST);
++}
++
++/*
++ * Display
++ */
++$filesView = new CView('experiments.conf');
++
++$filesView->set('conf', expconfig_getuserconfig());
++
++$filesView->render();
++$filesView->show();
++
++require_once dirname(__FILE__).'/include/page_footer.php';
+diff --git conf/.gitignore conf/.gitignore
+new file mode 100644
+index 0000000..d6cdf1c
+--- /dev/null
++++ conf/.gitignore
+@@ -0,0 +1 @@
++zabbix.conf.php
+diff --git dashboard.php dashboard.php
+index fe17a67..e71abb8 100644
+--- dashboard.php
++++ dashboard.php
+@@ -253,6 +253,11 @@ insert_js('var page_menu='.zbx_jsvalue($menu).";\n".'var 
page_submenu='.zbx_jsva
+  */
+ $leftColumn = array();
+ 
++// Manage monitoring
++$manage_wdgt = new CUIWidget('hat_managemonitoring', 
make_manage_monitoring(), 1);
++$manage_wdgt->setHeader(_('Manage Monitoring'));
++$leftColumn[] = $manage_wdgt;
++
+ // favorite graphs
+ $graph_menu = get_icon('menu', array('menu' => 'graphs'));
+ $fav_grph = new CUIWidget('hat_favgrph', make_favorite_graphs(), 
CProfile::get('web.dashboard.hats.hat_favgrph.state', 1));
+@@ -297,6 +302,12 @@ if ($USER_DETAILS['type'] == USER_TYPE_SUPER_ADMIN) {
+       $rightColumn[] = $zbxStatus;
+ }
+ 
++// run scripts
++$scripts_wdgt = new CUIWidget('hat_runscripts', make_run_scripts(), 1);
++$scripts_wdgt->setHeader(_('Run Scripts'));
++//$scripts_wdgt->setFooter(new CLink(_('Graphs').' &raquo;', 'charts.php', 
'highlight'), true);
++$rightColumn[] = $scripts_wdgt;
++
+ // system status
+ $refresh_menu = new CIcon(_('Menu'), 'iconmenu', 
'create_page_menu(event,"hat_syssum");');
+ $sys_stat = new CUIWidget('hat_syssum', new CSpan(_('Loading...'), 
'textcolorstyles'), CProfile::get('web.dashboard.hats.hat_syssum.state', 1));
+diff --git execute.php execute.php
+new file mode 100644
+index 0000000..0428d3e
+--- /dev/null
++++ execute.php
+@@ -0,0 +1,69 @@
++<?php
++
++require_once dirname(__FILE__).'/include/config.inc.php';
++require_once dirname(__FILE__).'/include/experiments/inc.php';
++
++$page['title'] = _('Deploy & Execute');
++$page['file'] = 'execute.php';
++$page['hist_arg'] = array('execid');
++
++require_once dirname(__FILE__).'/include/page_header.php';
++
++// VAR        TYPE    OPTIONAL        FLAGS   VALIDATION      EXCEPTION
++/*$fields = array(
++      'run' =>                array(T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, 
null),
++      'nodes' =>              array(T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, 
'isset({run})'),
++      'usetasklist' =>   array(T_ZBX_INT, O_OPT, P_SYS|P_ACT, IN('0,1'), 
'isset({run})'),
++      'tasklist' =>   array(T_ZBX_INT, O_OPT, P_SYS|P_ACT, null, 
'isset({run})'),
++      'cmd' =>   array(T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, 'isset({run})'),
++      'sync' =>   array(T_ZBX_INT, O_OPT, null, null, null)
++);
++check_fields($fields);*/
++
++
++/*
++ * Actions
++ */
++
++if(isset($_REQUEST['run']))
++{
++    $usetasklist = intval($_REQUEST['usetasklist']);
++    $tasklist = intval($_REQUEST['tasklist']);
++
++    $cmd = trim($_REQUEST['cmd']);
++    $cmd_empty = empty($cmd);
++    
++    if($usetasklist == 0 && $cmd_empty)
++        error("Please specify the command to run.");
++    elseif(!isset($_REQUEST['target']))
++        error("Please specify target.");
++    elseif(!isset($_REQUEST['hosts']) || count($_REQUEST['hosts']) == 0)
++        error("Please specify hosts to run");
++    else
++    {
++        $res = exprun_new($_REQUEST['target'], $_REQUEST['hosts'], 
$usetasklist, $tasklist, $cmd);
++        if($res == EXP_ERR_GPLMT_DIR)
++            error("Could not verify GPLMT files, please make sure that they 
exist and write permissions are enabled.");
++        elseif($res == EXP_ERR_PERMISSION)
++            error("Permission error.");
++        elseif($res == EXP_ERR_INVALID_TARGET)
++            error("Invalid target!");
++        else
++            jsRedirect('results.php');
++    }
++}
++
++/*
++ * Display
++ */
++
++$execView = new CView('experiments.execute');
++
++$execView->set('tasklists', exptasklist_getall());
++$execView->set('targets', $exp_targetlist);
++$execView->set('currenttarget', 
isset($_REQUEST['target'])?$_REQUEST['target']:reset($exp_targetlist));
++
++$execView->render();
++$execView->show();
++
++require_once dirname(__FILE__).'/include/page_footer.php';
+diff --git files.php files.php
+new file mode 100644
+index 0000000..5326ccc
+--- /dev/null
++++ files.php
+@@ -0,0 +1,58 @@
++<?php
++
++require_once dirname(__FILE__).'/include/config.inc.php';
++require_once dirname(__FILE__).'/include/experiments/inc.php';
++
++$page['title'] = _('User Files');
++$page['file'] = 'files.php';
++$page['hist_arg'] = array('fileid');
++
++//before any headers are written, check if trying to download
++if(isset($_REQUEST['download']))
++{
++    $filename = $_REQUEST['download'];
++    
++    expfiles_download($filename);
++}
++
++require_once dirname(__FILE__).'/include/page_header.php';
++
++// VAR        TYPE    OPTIONAL        FLAGS   VALIDATION      EXCEPTION
++/*$fields = array(
++);
++check_fields($fields);*/
++
++/*
++ * Actions
++ */
++if(isset($_REQUEST['upload']) && isset($_FILES['file']))
++{
++    //some validations
++    if($_FILES["file"]["error"] > 0)
++        error('File upload error: '.$_FILES["file"]["error"]);
++    else
++    {
++        $filename = $_FILES["file"]["name"];
++        $fullpath = expfiles_getnewfilepath($filename);
++        move_uploaded_file($_FILES["file"]["tmp_name"], $fullpath);
++        
++        info("File uploaded successfully.");
++    }
++}
++if(isset($_REQUEST['delete']))
++{
++    if(expfiles_delete($_REQUEST['delete'])) jsRedirect('files.php');
++}
++
++/*
++ * Display
++ */
++$filesView = new CView('experiments.files');
++
++$filesView->set('files', expfiles_getuserfiles());
++
++$filesView->render();
++$filesView->show();
++
++
++require_once dirname(__FILE__).'/include/page_footer.php';
+diff --git images/general/question_mark.png images/general/question_mark.png
+new file mode 100644
+index 
0000000000000000000000000000000000000000..8dee9d00722e31f2c56938ff1e64325fe2f89463
+GIT binary patch
+literal 618
+zcmV-w0+s!VP)<h;3K|address@hidden&`wG00006VoOIv0RI60
+z0RN!9r;`8x010qNS#tmY3zYx>3zY$-s#FjF000McNliru-3bN}3<eTCyMh1!0ryEn
+zK~yNuZPGn#5^)address@hidden)}uBpFD43<address@hidden)ojSQR
+zF1EYWrHz(J6ExJO24Qe21&<Jrk`x0aSNLD=j^lnV)tKlrKil`iaI(4en(ce5e>Wa>
+zC1L?F3IN;tN;address@hidden;@+UBiL|MwS>RVlELY36#GL9%L4uEFVRgHz|&Ag&p-kZI;3
+zt5N^}*xY)}HtlupEL}Z)>address@hidden
+z8T2yWHa*Kll2yaJ{jN^;QVo(-!yH>K(Ti-$<eEW~E9H4hJnTy7Ca_WJvMT`>y_LEw
+zC2_poJ3^tYvG}-1sdA4g1|c4HC9JWa7?nCY4ip2$L!Eu7a=3>CTt4fB+bLkDam=g&
+z!(LlQEGR~;address@hidden;address@hidden>M(qfV*gym#
+z02h1?Y?e8sLmh&J(K)address@hidden|)?A~Aqj7}1+T7aPSR2n<93i}{^2
+z>R?D$cv6_T|D;fA_isF(_4#Ghq>gH`sDB7&hOICGc5`Bwp3QpM(wBCA0DAl<++wDg
+zQ*?v&Wt}p$9(}6z=!dKk*9>~P^;fw6(g>c=sQ*jj7e7}JB#9c$K>z>%07*qoM6N<$
+Eg6%X1fdBvi
+
+literal 0
+HcmV?d00001
+
+diff --git include/blocks.inc.php include/blocks.inc.php
+index 3896140..7b1321a 100644
+--- include/blocks.inc.php
++++ include/blocks.inc.php
+@@ -1401,3 +1401,174 @@ function makeTriggersPopup(array $triggers, array 
$ackParams) {
+ 
+       return $popupTable;
+ }
++
++function make_run_scripts()
++{
++      //create big table
++      $bigTable = new CTableInfo();
++      
++    //create table 1
++    $scriptsTable = new CTableInfo(_('No scripts defined.'));
++    $scriptsTable->setHeader(array(
++          _('Name'),
++          _('Run on Host'),
++          _('Run on Host Group')
++    ));
++    
++    //get list of scripts
++    $scripts = API::Script()->get(array(
++              'output' => array('name')
++      ));
++      
++      //get list of hosts
++      $hosts = API::Host()->get(array(
++              'sortfield' => 'name',
++              'output' => array('name')
++      ));
++      
++      //get list of host groups
++    $hostgroups = API::HostGroup()->get(array(
++              'sortfield' => 'name',
++              'output' => array('name')
++      ));
++      
++      //add rows
++      foreach($scripts as $script)
++      {
++          //create hostgroups combobox & run button
++        $runForm = new CForm('GET', 'scripts_exec.php');
++        $runForm->attr("target", "_blank");
++        $runForm->addItem(new CInput('hidden', 'execute', '1'));
++        $runForm->addItem(new CInput('hidden', 'scriptid', 
$script['scriptid']));
++        
++        $grpsComboBox = new CComboBox('groupid');
++        foreach($hostgroups as $hostgroup)
++            $grpsComboBox->addItem(new CComboItem($hostgroup['groupid'], 
$hostgroup['name']));
++
++        $runForm->addItem($grpsComboBox);
++        $runForm->addItem(new CInput('submit', 'submit', 'Run'));
++        
++        //create hosts combobox & run button
++        $runFormHosts = new CForm('GET', 'scripts_exec.php');
++        $runFormHosts->attr("target", "_blank");
++        $runFormHosts->addItem(new CInput('hidden', 'execute', '1'));
++        $runFormHosts->addItem(new CInput('hidden', 'scriptid', 
$script['scriptid']));
++        
++        $hostsComboBox = new CComboBox('hostid');
++        foreach($hosts as $host)
++            $hostsComboBox->addItem(new CComboItem($host['hostid'], 
$host['name']));
++
++        $runFormHosts->addItem($hostsComboBox);
++        $runFormHosts->addItem(new CInput('submit', 'submit', 'Run'));
++        
++        $scriptsTable->addRow(array(
++                  new CLink($script['name'], 
'scripts.php?form=1&scriptid='.$script['scriptid']),
++                  $runFormHosts,
++                  $runForm
++          ));
++      }
++      
++      //create multiple run form
++      $multForm = new CFormTable(null, 'scripts_exec.php', 'GET');
++      
++      $scriptsCmbbox = new CComboBox('scriptid');
++      foreach($scripts as $script)
++              $scriptsCmbbox->addItem(new CComboItem($script['scriptid'], 
$script['name']));
++      
++      $hostsListBox = new CListBox('hosts[]', null, 15);
++      foreach($hosts as $host)
++        $hostsListBox->addItem(new CComboItem($host['hostid'], 
$host['name']));
++    
++    $multForm->addRow($scriptsCmbbox);
++    $multForm->addRow($hostsListBox);
++    $multForm->attr("target", "_blank");
++    $multForm->addRow(new CInput('hidden', 'execute', '1'), new 
CInput('submit', 'submit', 'Run'));
++    
++    $bigTable->addRow(array(
++      $scriptsTable,
++      $multForm
++    ));
++    
++    return $bigTable;
++}
++
++function template_items_status($template_id)
++{
++      //fetch main template    
++    $options = array(
++              'templateids' => array($template_id),
++              'selectItems' => array('status'),
++              'output' => array('name')
++      );
++
++      $template = API::Template()->get($options);
++      
++      $total = 0;
++      $enabled = 0;
++      
++      foreach($template[0]['items'] as $item)
++      {
++              $total++;
++              if($item['status'] == 0) $enabled++;
++      }
++      
++      return array('total' => $total, 'enabled' => $enabled);
++}
++
++function make_manage_monitoring()
++{
++    $templates = array(10001, 10176, 10177);
++    
++    //fetch important templates
++    $options = array(
++              'templateids' => $templates,
++              'output' => array('name')
++      );
++      $templates = API::Template()->get($options);
++      
++      //create link/unlink all forms
++      $linkAllForm = new CForm('POST', 'manage_monitoring.php');
++      $unlinkAllForm = new CForm('POST', 'manage_monitoring.php');
++      foreach($templates as $temp)
++      {
++              $linkAllForm->addItem(new CInput('hidden', 
'template['.$temp['hostid'].']', $temp['hostid']));
++              $unlinkAllForm->addItem(new CInput('hidden', 
'template['.$temp['hostid'].']', $temp['hostid']));
++      }
++      $linkAllForm->addItem(new CInput('submit', 'submit', 'Enable All'));
++    $linkAllForm->addItem(new CInput('hidden', 'action', 'enable'));
++
++      $unlinkAllForm->addItem(new CInput('submit', 'submit', 'Disable All'));
++    $unlinkAllForm->addItem(new CInput('hidden', 'action', 'disable'));
++      
++      //table that will contain forms
++      $table = new CTable();
++      
++      foreach($templates as $template)
++      {
++              $items_status = template_items_status($template['hostid']);
++              
++          $r = new CRow();
++          $r->addItem(new CLabel($template['name'] . ' [' . 
$items_status['enabled'] . '/' . $items_status['total'] . ']'));
++          
++          $enableForm = new CForm('POST', 'manage_monitoring.php');
++          $enableForm->addItem(new CInput('hidden', 
'template['.$template['hostid'].']', $template['hostid']));
++          $enableForm->addItem(new CInput('submit', 'submit', 'Disable'));
++        $enableForm->addItem(new CInput('hidden', 'action', 'disable'));
++          
++          $disableForm = new CForm('POST', 'manage_monitoring.php');
++        $disableForm->addItem(new CInput('hidden', 
'template['.$template['hostid'].']', $template['hostid']));
++      $disableForm->addItem(new CInput('submit', 'submit', 'Enable'));
++      $disableForm->addItem(new CInput('hidden', 'action', 'enable'));
++
++          $r->addItem($enableForm);        
++          $r->addItem($disableForm);
++          
++          $table->addRow($r);
++      }
++      $totalRows = new CRow();
++      $totalRows->addItem($linkAllForm);
++      $totalRows->addItem($unlinkAllForm);
++      $table->addRow($totalRows);
++      
++      return $table;
++}
+diff --git include/classes/import/CXmlImport18.php 
include/classes/import/CXmlImport18.php
+index b03a3bc..b101cbf 100644
+--- include/classes/import/CXmlImport18.php
++++ include/classes/import/CXmlImport18.php
+@@ -1003,7 +1003,7 @@ class CXmlImport18 {
+                               $host_db['groups'] = array();
+                               $groups_to_parse = array();
+                               foreach ($groups as $group) {
+-                                      $groups_to_parse[] = array('name' => 
$group->nodeValue);
++                                      $groups_to_parse[] = array('name' => 
trim($group->nodeValue));
+                               }
+                               if (empty($groups_to_parse)) {
+                                       $groups_to_parse[] = array('name' => 
ZBX_DEFAULT_IMPORT_HOST_GROUP);
+@@ -1134,6 +1134,7 @@ class CXmlImport18 {
+ 
+                                       $templateLinkage = array();
+                                       foreach ($templates as $template) {
++                                              $template->nodeValue = 
trim($template->nodeValue);
+                                               $options = array(
+                                                       'filter' => 
array('host' => $template->nodeValue),
+                                                       'output' => 
API_OUTPUT_SHORTEN,
+diff --git include/experiments/conf.php include/experiments/conf.php
+new file mode 100644
+index 0000000..9bef025
+--- /dev/null
++++ include/experiments/conf.php
+@@ -0,0 +1,9 @@
++<?php
++
++$GLOBALS['GPLMT_DIR'] = '/home/omar/workspace/gnunet-planetlab/gplmt/';
++
++$GLOBALS['GPLMT_TASKLISTS_DIR'] = $GLOBALS['GPLMT_DIR'].'contrib/tasklists/';
++$GLOBALS['GPLMT_CONF_DIR'] = $GLOBALS['GPLMT_DIR'].'contrib/configurations/';
++$GLOBALS['GPLMT_NODES_DIR'] = $GLOBALS['GPLMT_DIR'].'contrib/nodes/';
++$GLOBALS['GPLMT_RESULTS_DIR'] = $GLOBALS['GPLMT_DIR'].'contrib/results/';
++$GLOBALS['GPLMT_FILES_DIR'] = $GLOBALS['GPLMT_DIR'].'contrib/files/';
+diff --git include/experiments/config.php include/experiments/config.php
+new file mode 100644
+index 0000000..1e4ed5a
+--- /dev/null
++++ include/experiments/config.php
+@@ -0,0 +1,106 @@
++<?php
++
++function expconfig_update($data)
++{
++    //get user editable config
++    $editable = expconfig_getuserconfig();
++    
++    foreach($data as $k => $v)
++    {
++        if(!isset($editable[$k])) continue;
++        $v = trim($v);
++        $enabled = ($v != '');
++        
++        if(($editable[$k]['type'] == 'file') && $enabled)
++            $v = expfiles_getuserdir().exp_cleanfilename($v);
++        
++        expdb_update('exp_userconfig',
++            array('value' => $v, 'enabled' => strval($enabled)),
++            array('configid' => $k, 'userid' => CWebUser::$data['userid']));
++    }
++    
++    expconfig_writefile();
++}
++
++function expconfig_getconfigbyname($configname)
++{
++    $uid = CWebUser::$data['userid'];
++    $sql = "SELECT exp_userconfig.value, exp_userconfig.enabled
++        FROM exp_config, exp_userconfig
++        WHERE exp_config.configid = exp_userconfig.configid
++        AND exp_config.name = '$configname'
++        AND exp_userconfig.userid = $uid";
++    $result = DBfetchArray(DBselect($sql));
++    if(count($result) == 0) return null;
++    if(!$result[0]['enabled']) return null;
++    return $result[0]['value'];
++}
++
++function expconfig_getuserconfig($editableOnly = true)
++{
++    $uid = CWebUser::$data['userid'];
++    $sql = "SELECT u.configid, c.section, c.name, c.label, c.description, 
c.type, u.value
++            FROM exp_config c, exp_userconfig u
++            WHERE c.configid = u.configid
++            AND c.user_editable = 1
++            AND u.userid = $uid
++            ORDER BY c.section, c.configid";
++    return DBfetchArrayAssoc(DBselect($sql), 'configid');
++}
++
++function expconfig_getenum($configid)
++{
++    return expdb_select('exp_configenum', array('configid' => $configid));
++}
++
++function expconfig_writefile()
++{
++    $uid = CWebUser::$data['userid'];
++    $sql = "SELECT c.section, c.name, u.value
++            FROM exp_config c, exp_userconfig u
++            WHERE c.configid = u.configid
++            AND u.enabled = 1
++            AND u.userid = $uid
++            ORDER BY c.section";
++    $conf = DBfetchArray(DBselect($sql));
++    
++    $filename = $GLOBALS['GPLMT_CONF_DIR'].strval($uid);
++    $f = fopen($filename, 'w+');
++    $current_sec = '';
++    
++    foreach($conf as $c)
++    {
++        if($c['section'] != $current_sec)
++        {
++            $current_sec = $c['section'];
++            fwrite($f, "[$current_sec]\n");
++        }
++        $k = $c['name'];
++        $v = $c['value'];
++        fwrite($f, "$k = $v\n");
++    }
++    fclose($f);
++}
++
++function expconfig_verifyuserconfig()
++{
++    $uid = CWebUser::$data['userid'];
++    $default_config = expdb_select('exp_config', array(), 'configid');
++    $user_config = expdb_select('exp_userconfig', array('userid' => $uid), 
'configid');
++    
++    if(count($default_config) == count($user_config)) return;
++    
++    foreach($default_config as $dc_k => $dc)
++    {
++        if(isset($user_config[$dc_k])) continue;
++        
++        $newval = $dc['default_value'];
++        if($dc['name'] == 'userdir') //special cases, user specific
++            $newval = expfiles_getuserdir();
++        $enabled = strval(($newval != ''));
++        
++        expdb_insert('exp_userconfig',
++            array('configid' => $dc_k, 'userid' => $uid, 'value' => $newval, 
'enabled' => $enabled));
++    }
++    expconfig_writefile();
++}
+diff --git include/experiments/db.php include/experiments/db.php
+new file mode 100644
+index 0000000..14f1b7c
+--- /dev/null
++++ include/experiments/db.php
+@@ -0,0 +1,85 @@
++<?php
++
++function expdb_genwhere($where)
++{
++    if(sizeof($where) == 0) return '';
++    
++    $where_str = ' WHERE ';
++    
++    $first = true;
++    foreach($where as $k => $v)
++    {
++        if(!$first) $where_str .= ' AND ';
++        else $first = false;
++        $where_str .= $k.'=';
++        if(is_string($v))
++            $where_str .= ("'".mysql_real_escape_string(trim($v))."'");
++        else
++            $where_str .= $v;
++    }
++    
++    return $where_str;
++}
++
++function expdb_insert($table, $data)
++{
++    $keys_str = implode(',', array_keys($data));
++    
++    $vals = array();
++    foreach($data as $v)
++    {
++        if(is_string($v)) $vals[] = 
"'".mysql_real_escape_string(trim($v))."'";
++        else $vals[] = $v;
++    }
++    
++    $vals_str = implode(',', $vals);
++    
++    $sql = "INSERT INTO $table ($keys_str) VALUES ($vals_str)";
++    
++    DBexecute($sql);
++    return mysql_insert_id(); #TODO: mysql specific, need to be changed to be 
generic
++}
++
++function expdb_update($table, $data, $where)
++{
++    $set_str = '';
++    $first = true;
++    foreach($data as $k => $v)
++    {
++        if(!$first) $set_str .= ',';
++        else $first = false;
++        $set_str .= $k.'=';
++        if(is_string($v))
++            $set_str .= ("'".mysql_real_escape_string(trim($v))."'");
++        else
++            $set_str .= $v;
++    }
++    
++    $where_str = expdb_genwhere($where);
++    
++    $sql = "UPDATE $table SET $set_str $where_str";
++    
++    return DBexecute($sql);
++}
++
++
++function expdb_select($table, $where, $assocField = null)
++{
++    $where_str = expdb_genwhere($where);
++    
++    $sql = "SELECT * FROM $table $where_str";
++    
++    if($assocField)
++        return DBfetchArrayAssoc(DBselect($sql), $assocField);
++    else
++        return DBfetchArray(DBselect($sql));
++}
++
++function expdb_delete($table, $where)
++{
++    $where_str = expdb_genwhere($where);
++    
++    $sql = "DELETE FROM $table $where_str";
++    
++    return DBexecute($sql);
++}
+diff --git include/experiments/files.php include/experiments/files.php
+new file mode 100644
+index 0000000..a2f5fe8
+--- /dev/null
++++ include/experiments/files.php
+@@ -0,0 +1,82 @@
++<?php
++
++/*
++ * Get the full path for the directory containing the user personal file
++ */
++function expfiles_getuserdir()
++{
++    $uid = CWebUser::$data['userid'];
++    $dir = $GLOBALS['GPLMT_FILES_DIR'].strval($uid).'/';
++    if(!file_exists($dir)) mkdir($dir);
++    return $dir;
++}
++
++/*
++ * Returns an array with the names of files inside the user personal directory
++ */
++function expfiles_getuserfiles()
++{
++    $dirpath = expfiles_getuserdir();
++    
++    $res = scandir($dirpath);
++    $res = array_diff($res, array('.', '..'));
++    return $res;
++}
++
++/*
++ * Given a file name for a new file to be uploaded, returns a full path 
++ * with the same or modified filename if already exists
++ */
++function expfiles_getnewfilepath($filename = 'new')
++{
++    $filename = exp_cleanfilename($filename);
++    $dirpath = expfiles_getuserdir();
++    
++    $parts = explode('.', $filename);
++    $orig = $parts[0];
++    
++    $counter = 0;
++    while(file_exists($dirpath.implode('.', $parts)))
++    {
++        $parts[0] = $orig.strval($counter);
++        $counter++;
++    }
++    
++    return $dirpath.implode('.', $parts);
++}
++
++function expfiles_delete($filename)
++{
++    $filename = exp_cleanfilename($filename);
++    $fullpath = expfiles_getuserdir().$filename;
++    if(file_exists($fullpath)) unlink($fullpath);
++    return true;
++}
++
++function expfiles_download($filename)
++{
++    $filename = exp_cleanfilename($filename);
++    $fullpath = expfiles_getuserdir().$filename;
++    if(!file_exists($fullpath))
++    {
++        error("File doesn't exist");
++        return false;
++    }
++    
++    $size = filesize($fullpath);
++    $mime_type="application/force-download";
++    
++    //@ob_end_clean();
++    
++    header('Content-Type: ' . $mime_type);
++    header('Content-Disposition: attachment; filename="'.$filename.'"');
++    header("Content-Transfer-Encoding: binary");
++    header('Accept-Ranges: bytes');
++    header("Cache-control: private");
++    header('Pragma: private');
++    header('Content-Length: ' . $size);
++    ob_clean();
++    flush();
++    readfile($fullpath); 
++    exit;
++}
+diff --git include/experiments/inc.php include/experiments/inc.php
+new file mode 100644
+index 0000000..0823b39
+--- /dev/null
++++ include/experiments/inc.php
+@@ -0,0 +1,50 @@
++<?php
++
++require_once dirname(__FILE__).'/conf.php';
++require_once dirname(__FILE__).'/db.php';
++require_once dirname(__FILE__).'/tasklist.php';
++require_once dirname(__FILE__).'/run.php';
++require_once dirname(__FILE__).'/files.php';
++require_once dirname(__FILE__).'/config.php';
++require_once dirname(__FILE__).'/nodes.php';
++require_once dirname(__FILE__).'/targets.php';
++
++define('EXP_OK', '0');
++define('EXP_ERR_GPLMT_DIR', '1');
++define('EXP_ERR_PERMISSION', '2');
++define('EXP_ERR_INVALID_TARGET', '3');
++
++
++function exp_cleanfilename($filename)
++{
++    return preg_replace("/[^a-z0-9\.]/", "", strtolower($filename));
++}
++
++
++function exp_gettargets()
++{
++    $cmd = 'python '.$GLOBALS['GPLMT_DIR'].'gplmt/Targets.py';
++    $res = array();
++    exec($cmd, $res);
++    return $res;
++}
++
++function exp_verifygplmtdir()
++{
++    if(!file_exists($GLOBALS['GPLMT_DIR'].'gplmt.py'))
++    {
++        error('GPLMT path invalid!');
++        return false;
++    }
++    
++    if(!file_exists($GLOBALS['GPLMT_TASKLISTS_DIR'])) 
mkdir($GLOBALS['GPLMT_TASKLISTS_DIR']);
++    if(!file_exists($GLOBALS['GPLMT_CONF_DIR'])) 
mkdir($GLOBALS['GPLMT_CONF_DIR']);
++    if(!file_exists($GLOBALS['GPLMT_NODES_DIR'])) 
mkdir($GLOBALS['GPLMT_NODES_DIR']);
++    if(!file_exists($GLOBALS['GPLMT_RESULTS_DIR'])) 
mkdir($GLOBALS['GPLMT_RESULTS_DIR']);
++    if(!file_exists($GLOBALS['GPLMT_FILES_DIR'])) 
mkdir($GLOBALS['GPLMT_FILES_DIR']);
++    
++    return true;
++}
++
++exp_verifygplmtdir();
++expconfig_verifyuserconfig();
+diff --git include/experiments/nodes.php include/experiments/nodes.php
+new file mode 100644
+index 0000000..08a4f22
+--- /dev/null
++++ include/experiments/nodes.php
+@@ -0,0 +1,88 @@
++<?php
++
++function expnodes_getbyrunid($run_id)
++{
++    $run_id = mysql_real_escape_string($run_id);
++    
++    $sql = "SELECT exp_host.hostid, exp_host.host
++            FROM exp_runnode, exp_host
++            WHERE exp_runnode.hostid = exp_host.hostid
++            AND exp_runnode.runid = $run_id";
++    
++    return DBfetchArray(DBselect($sql));
++}
++
++function expnodes_writefile($nodes, $run_id)
++{
++    $nodes_file = $GLOBALS['GPLMT_NODES_DIR'].$run_id;
++    
++    $f = fopen($nodes_file, 'w+');
++    foreach($nodes as $n) fwrite($f, "$n\n");
++    fclose($f);
++}
++
++function expnodes_gethosts($target)
++{
++    $userid = CWebUser::$data['userid'];
++    return expdb_select('exp_host', array('userid' => $userid, 'target' => 
$target));
++}
++
++function expnodes_gethostbyid($hostid)
++{
++    $res = expdb_select('exp_host', array('hostid' => $hostid));
++    if(count($res) == 0) return null;
++    return $res[0];
++}
++
++function expnodes_gethostinterface($hostid)
++{
++    $h = API::Host()->get(array(
++        'hostids' => $hostid,
++        'output' => array(),
++        'selectInterfaces' => API_OUTPUT_EXTEND
++    ));
++    
++    if(count($h) == 0) return '';
++    foreach($h[0]['interfaces'] as $i)
++    {
++        if($i['main'] == 1)
++        {
++            if($i['useip'] == 1) return $i['ip'];
++            else return $i['dns'];
++        }
++    }
++}
++
++function expnodes_getzabbixnodes()
++{
++    $hosts = API::Host()->get(array(
++        'output' => array('hostid', 'host'),
++        'selectInterfaces' => API_OUTPUT_EXTEND
++    ));
++    
++    $nodes = array();
++    
++    foreach($hosts as $h)
++    {
++        $n = array();
++        $n['hostid'] = $h['hostid'];
++        $n['host'] = $h['host'];
++        
++        foreach($h['interfaces'] as $i)
++        {
++            if($i['main'] == 1)
++            {
++                $n['interfaceid'] = $i['interfaceid'];
++                if($i['useip'] == 1) $n['interface'] = $i['ip'];
++                else $n['interface'] = $i['dns'];
++                
++                break;
++            }
++        }
++        
++        $nodes[] = $n;
++    }
++    
++    return $nodes;
++}
++
+diff --git include/experiments/run.php include/experiments/run.php
+new file mode 100644
+index 0000000..c0d0700
+--- /dev/null
++++ include/experiments/run.php
+@@ -0,0 +1,290 @@
++<?php
++
++define('EXP_STATUS_FAILED', -1);
++define('EXP_STATUS_NOT_STARTED', 0);
++define('EXP_STATUS_RUNNING', 1);
++define('EXP_STATUS_DONE_WITH_ERRORS', 2);
++define('EXP_STATUS_DONE_SUCCESSFULLY', 10);
++
++function exprun_getstatusstring($status)
++{
++    switch($status)
++    {
++        case -1:
++            return "Failed";
++        case 0:
++            return "Not started";
++        case 1:
++            return "Running";
++        case 2:
++            return "Done with errors";
++        case 10:
++            return "Done successfully";
++        default:
++            return "Undefined status";
++    }
++}
++
++function exprun_getall($extended = false, $string_status = true)
++{
++    exprun_updateresults(); //update database with any new results
++
++    $where['userid'] = intval(CWebUser::$data['userid']);
++
++    $res = expdb_select('exp_run', $where);
++    
++    for($i = 0; $i < sizeof($res); $i++)
++    {
++        $sql = "SELECT exp_runnode.*, exp_host.host as interface FROM 
exp_runnode, exp_host
++                WHERE exp_runnode.runid = ".$res[$i]['runid']."
++                AND exp_runnode.hostid = exp_host.hostid
++                ORDER BY exp_runnode.status DESC, exp_runnode.percentage 
DESC, exp_host.host ASC";
++        $nodes = DBfetchArray(DBselect($sql));
++        
++        if($string_status)
++            $res[$i]['status'] = exprun_getstatusstring($res[$i]['status']);
++        
++        for($j = 0; $j < sizeof($nodes); $j++)
++        {
++            if($string_status)
++                $nodes[$j]['status'] = 
exprun_getstatusstring($nodes[$j]['status']);
++        }
++        
++        $res[$i]['nodes'] = $nodes;
++    }
++    
++    return $res;
++}
++
++function exprun_updateresults()
++{
++    $running = expdb_select('exp_run', array('status' => 1));
++    foreach($running as $r)
++    {
++        $updates = exprun_parseresult($r['runid']);
++        expdb_update('exp_run', array('status' => $updates['status'], 
'percentage' => $updates['percentage']), array('runid' => $r['runid']));
++        foreach($updates['nodes_results'] as $nr)
++        {
++            expdb_update('exp_runnode',
++                array('status' => $nr['status'], 'percentage' => 
$nr['percentage'], 'log' => $nr['log']),
++                array('runid' => $r['runid'], 'hostid' => $nr['hostid']));
++        }
++    }
++}
++
++function exprun_pidrunning($pid)
++{
++    $cmd = "ps --no-headers -p ".$pid;
++    $res = exec($cmd);
++    return !empty($res);
++}
++
++function exprun_calculatestatus($percentage, $running, $failure)
++{
++    if($percentage < 100) $status = ($running) ? EXP_STATUS_RUNNING : 
EXP_STATUS_FAILED;
++    else $status = ($failure) ? EXP_STATUS_DONE_WITH_ERRORS : 
EXP_STATUS_DONE_SUCCESSFULLY;
++    return $status;
++}
++
++function exprun_parseresult($run_id)
++{
++    $prog = 0;
++    $total = 1;
++    $failure = false;
++    $nodes_results = array();
++    
++    //Read metadata
++    $meta = exprun_getbyid($run_id);
++    
++    //Check if the process is already running
++    $running = exprun_pidrunning($meta['pid']);
++
++    $results_file = $GLOBALS['GPLMT_RESULTS_DIR'].$run_id;
++    if(file_exists($results_file))
++    {
++        //Read nodes from DB
++        $nodes = expnodes_getbyrunid($run_id);
++
++        //Read loaded tasks (if available)
++        if($meta['usetasklist'])
++            $tasks = exec('grep -Po "(?<=Loaded )\d+(?= tasks)" 
'.$results_file);
++        else
++            $tasks = 1;
++        if(!empty($tasks))
++        {
++            $tasks = intval($tasks);
++
++            $total = count($nodes) * $tasks;
++
++            //for each node, calculate progress from result output    
++            foreach($nodes as $n)
++            {
++                $node_failure = false;
++                $interface = $n['host'];
++
++                $res = array();
++                exec('grep -Po "'.$interface.'\s*\| .* \| \K.*" 
'.$results_file, $res); //final result
++                if(count($res) > 0)
++                {
++                    if(trim($res[0]) != 'success')
++                    {
++                        $failure = true;
++                        $node_failure = true;
++                    }
++                    $node_prog = $tasks;
++                }
++                else
++                {
++                    //tasks completed for node
++                    $tasks_completed = array();
++                    exec('grep -Po "'.$interface.' : Task \'.*\' completed" 
'.$results_file, $tasks_completed);
++                    $node_prog = count($tasks_completed);
++                }
++                
++                //get all node logs
++                $node_log_arr = array();
++                exec("grep -E '^$interface' $results_file", $node_log_arr);
++                $node_log = implode("\n", $node_log_arr);
++                
++                $node_perc = $node_prog * 100 / $tasks;
++                $nodes_results[] = array('status' => 
exprun_calculatestatus($node_perc, $running, $node_failure),
++                                    'percentage' => ($running) ? $node_perc : 
100,
++                                    'log' => $node_log,
++                                    'hostid' => $n['hostid']);
++                $prog += $node_prog;
++            }
++        }
++    }
++    
++    $perc = $prog * 100 / $total; //percentage done
++    $status = exprun_calculatestatus($perc, $running, $failure); //total 
status
++    
++    return array('status' => $status, 'percentage' => ($running) ? $perc : 
100, 'nodes_results' => $nodes_results);
++}
++
++function exprun_new($target, $params, $usetasklist, $tasklist, $cmd)
++{
++    if(!exp_verifygplmtdir()) return EXP_ERR_GPLMT_DIR;
++    if($usetasklist == 1 && exptasklist_allowed($tasklist) == 0) return 
EXP_ERR_PERMISSION;
++    
++    //create run record
++    $run_data = array();
++    $run_data['usetasklist'] = $usetasklist;
++    if($usetasklist == 1)
++        $run_data['tasklistid'] = $tasklist;
++    else
++        $run_data['command'] = $cmd;
++    $run_data['userid'] = intval(CWebUser::$data['userid']);
++    $run_data['target'] = $target;
++    
++    $run_id = expdb_insert('exp_run', $run_data);
++
++    //create run-nodes records
++    switch($target)
++    {
++        case 'ssh':
++        case 'planetlab':
++            $hostnames = array();
++            foreach($params as $h) //get hostnames and save to DB
++            {
++                $hostinfo = expnodes_gethostbyid($h); $hostnames[] = 
$hostinfo['host'];
++                expdb_insert('exp_runnode', array('runid' => $run_id, 
'hostid' => $h, 'target' => $target));
++            }
++            //write GPLMT nodes file
++            expnodes_writefile($hostnames, $run_id);
++            break;
++            
++        default: //invalid target
++            expdb_delete('exp_run', array('runid' => $run_id));
++            return EXP_ERR_INVALID_TARGET;
++    }
++    
++    exprun_gplmt($run_id);
++    
++    return EXP_OK;
++}
++
++function exprun_getbyid($run_id)
++{
++    $res = expdb_select('exp_run', array('runid' => $run_id));
++    return $res[0];
++}
++
++function exprun_rerun($run_id)
++{
++    $meta = exprun_getbyid($run_id);
++    if(exprun_pidrunning($meta['pid'])) return;
++    
++    exprun_gplmt($run_id);
++}
++
++function exprun_checkpermission($run_id)
++{
++    if(CWebUser::$data['type'] == 3) return true;
++    
++    $res = expdb_select('exp_run', array('userid' => 
CWebUser::$data['userid'], 'runid' => $run_id));
++    
++    return (sizeof($res) > 0);
++}
++
++function exprun_interrupt($run_id)
++{
++    $meta = exprun_getbyid($run_id);
++    
++    if(!exprun_checkpermission($run_id)) return;
++    
++    $cmd = "kill -15 ".$meta['pid'];
++    exec($cmd);
++}
++
++function exprun_delete($run_id)
++{
++    $meta = exprun_getbyid($run_id);    
++
++    //check permissions
++    if(!exprun_checkpermission($run_id)) return;
++    
++    //check if tool still running
++    if(exprun_pidrunning($meta['pid'])) return;
++
++    $n = $GLOBALS['GPLMT_NODES_DIR'].$run_id;
++    if(file_exists($n)) unlink($n);
++    $r = $GLOBALS['GPLMT_RESULTS_DIR'].$run_id;
++    if(file_exists($r)) unlink($r);
++    
++    expdb_delete('exp_run', array('runid' => $run_id));
++    expdb_delete('exp_runnode', array('runid' => $run_id));
++}
++
++function exprun_verifyid($run_id)
++{
++    $res = expdb_select('exp_run', array('runid' => $run_id));
++    return (sizeof($res) > 0);
++}
++
++function exprun_gplmt($run_id)
++{
++    $run_data = exprun_getbyid($run_id);
++    if($run_data['usetasklist'])
++        $tasklist_data = exptasklist_getbyid($run_data['tasklistid']);
++    
++    //compose and run command
++    $cmd = 'python -u '.$GLOBALS['GPLMT_DIR'].'gplmt.py -V'; // GPLMT
++    $cmd .= ' -c '.$GLOBALS['GPLMT_CONF_DIR'].CWebUser::$data['userid']; // 
Conf file
++    $cmd .= ' -n '.$GLOBALS['GPLMT_NODES_DIR'].$run_id; // Nodes file
++    if($run_data['target'] == 'ssh')
++        $cmd .= ' -t remote_ssh';
++    elseif($run_data['target'] == 'planetlab')
++        $cmd .= ' -t planetlab';
++    if($run_data['usetasklist'])
++        $cmd .= ' -l 
'.$GLOBALS['GPLMT_TASKLISTS_DIR'].$tasklist_data['fsname']; // Tasklist file
++    else
++        $cmd .= " -C '".$run_data['command']."'"; // Command to run
++    $cmd .= ' > '.$GLOBALS['GPLMT_RESULTS_DIR'].$run_id; // Results file
++    $cmd .= ' 2>&1 & echo $!'; // Redirect stderr, run in background and get 
pid
++    
++    $pid = system($cmd);
++
++    expdb_update("exp_run", array('fullcommand' => $cmd, 'pid' => $pid, 
'status' => EXP_STATUS_RUNNING), array('runid' => $run_id));
++}
++
+diff --git include/experiments/targets.php include/experiments/targets.php
+new file mode 100644
+index 0000000..3e3cc79
+--- /dev/null
++++ include/experiments/targets.php
+@@ -0,0 +1,184 @@
++<?php
++
++require_once 'XML/RPC2/Client.php';
++
++$exp_targetlist = array(
++    'SSH' => 'ssh',
++    'Planetlab' => 'planetlab');
++
++/*
++ * Planetlab
++ */
++
++function exppl_getauth()
++{
++    $pl_user = expconfig_getconfigbyname('username');
++    if(!$pl_user) fatal_error('Please specify planetlab username in config');
++    $pl_pass = expconfig_getconfigbyname('password');
++    if(!$pl_pass) fatal_error('Please specify planetlab password in config');
++    
++    return array(
++        "AuthMethod" => 'password',
++        "Username" => $pl_user,
++        "AuthString" => $pl_pass
++        );
++}
++
++function exppl_getclient()
++{
++    $pl_api = expconfig_getconfigbyname('api_url');
++    if(!$pl_api) fatal_error('Please specify planetlab API in config');
++    
++    return XML_RPC2_Client::create($pl_api, array('sslverify' => false));
++}
++
++function exppl_getslicename()
++{
++    $pl_slice = expconfig_getconfigbyname('slice');
++    if(!$pl_slice) fatal_error('Please specify planetlab slice in config');
++    return $pl_slice;
++}
++
++function exppl_getAvailableNodes($page_offset, $page_size, $hostfilter = null)
++{
++    $page_offset = intval($page_offset);
++    $page_size = intval($page_size);
++
++    $pl_slice = exppl_getslicename();
++    $auth = exppl_getauth();
++    $client = exppl_getclient();
++    
++    //get node IDs in slice (for negation)
++    try
++    {
++        $res = $client->GetSlices($auth, $pl_slice, array('node_ids')); 
$node_ids = $res[0]['node_ids'];
++    }
++    catch (XML_RPC2_FaultException $e)
++    {
++        fatal_error($e->getFaultCode() . ' : ' . $e->getFaultString());
++    }
++    
++    $filter = array('~node_id' => $node_ids,
++                    '-SORT' => 'hostname',
++                    '-OFFSET' => $page_offset,
++                    '-LIMIT' => $page_size);
++    if($hostfilter) $filter['hostname'] = "*$hostfilter*";
++    
++    try
++    {
++        return $client->GetNodes($auth, $filter, array('hostname', 
'node_id'));
++    }
++    catch (XML_RPC2_FaultException $e)
++    {
++        fatal_error($e->getFaultCode() . ' : ' . $e->getFaultString());
++    }
++}
++
++function exppl_getSliceNodes()
++{
++    $pl_slice = exppl_getslicename();
++    $auth = exppl_getauth();
++    $client = exppl_getclient();
++
++    //get node IDs
++    try
++    {
++        $res = $client->GetSlices($auth, $pl_slice, array('node_ids')); 
$node_ids = $res[0]['node_ids'];
++    }
++    catch (XML_RPC2_FaultException $e)
++    {
++        fatal_error($e->getFaultCode() . ' : ' . $e->getFaultString());
++    }
++    
++    //get node hostnames + IDs
++    try
++    {
++        $res = $client->GetNodes($auth, $node_ids, array('hostname', 
'node_id'));
++    }
++    catch (XML_RPC2_FaultException $e)
++    {
++        fatal_error($e->getFaultCode() . ' : ' . $e->getFaultString());
++    }
++    $res = exppl_updateSliceNodesDB($res);
++    return $res;
++}
++
++function exppl_updateSliceNodes($nodes)
++{
++    $pl_slice = exppl_getslicename();
++    $auth = exppl_getauth();
++    $client = exppl_getclient();
++    
++    try
++    {
++        $client->UpdateSlice($auth, $pl_slice, array('nodes' => 
array_map('intval', array_values($nodes))));
++    }
++    catch (XML_RPC2_FaultException $e)
++    {
++        fatal_error($e->getFaultCode() . ' : ' . $e->getFaultString());
++    }
++}
++
++function exppl_updateSliceNodesDB($nodes)
++{
++    if(!is_array($nodes)) return;
++    
++    $userid = CWebUser::$data['userid'];
++    
++    // No delete so as not to break previous runs
++    // Insert new hosts not seen before
++    
++    for($i = 0; $i < count($nodes); $i++)
++    {
++        if(!exppl_getHostByPLNodeId($nodes[$i]['node_id'])) //Does not exist
++            $nodes[$i]['hostid'] = expdb_insert('exp_host', array('userid' => 
$userid, 'host' => $nodes[$i]['hostname'], 'target' => 'planetlab', 'pl_nodeid' 
=> $nodes[$i]['node_id']));
++        else
++            { $res = exppl_getHostByPLNodeId($nodes[$i]['node_id']); 
$nodes[$i]['hostid'] = $res['hostid']; }
++    }
++    
++    return $nodes;
++}
++
++function exppl_getHostByPLNodeId($pl_nodeid)
++{
++    $res = expdb_select('exp_host', array('pl_nodeid' => $pl_nodeid));
++    if(count($res) == 0) return null;
++    return $res[0];
++}
++
++/*
++ * SSH
++ */
++
++function expssh_updatehosts($hostlist)
++{
++    if(!is_array($hostlist)) return;
++    
++    $userid = CWebUser::$data['userid'];
++    
++    $old_hostlist = array();
++    $new_hostlist = array();
++    foreach($hostlist as $h)
++    {
++        $hc = mysql_real_escape_string(trim($h));
++        if(!$hc) continue;
++        if(is_numeric($hc))
++            $old_hostlist[] = $hc;
++        else //added hosts value is the host itself not an ID
++            $new_hostlist[] = $hc;
++    }
++    
++    //look for deleted hosts
++    if(count($old_hostlist) > 0)
++    {
++        $sql = 'DELETE FROM exp_host
++            WHERE userid = '.$userid
++            .' AND target = "ssh"'
++            .' AND hostid NOT IN ('.implode(',', $old_hostlist).')';
++        DBexecute($sql);
++    }
++    
++    //look for new hosts
++    foreach($new_hostlist as $h)
++        expdb_insert('exp_host', array('userid' => $userid, 'host' => $h, 
'target' => 'ssh'));
++}
+diff --git include/experiments/tasklist.php include/experiments/tasklist.php
+new file mode 100644
+index 0000000..adf432c
+--- /dev/null
++++ include/experiments/tasklist.php
+@@ -0,0 +1,292 @@
++<?php
++
++require_once dirname(__FILE__).'/files.php';
++
++//default XML elements (for creating empty nods)
++$exptasklist_defaults = array();
++$exptasklist_defaults['sequence'] = new SimpleXMLElement('<sequence 
name=""></sequence>');
++$exptasklist_defaults['run'] = new SimpleXMLElement('<run 
name=""><command></command><arguments></arguments><timeout>0</timeout><expected_return_code>0</expected_return_code><expected_output></expected_output><stop_on_fail>false</stop_on_fail></run>');
++$exptasklist_defaults['run_per_host'] = new SimpleXMLElement('<run_per_host 
name=""><command_file></command_file><output_prefix></output_prefix><timeout>0</timeout><expected_return_code>0</expected_return_code><expected_output></expected_output><stop_on_fail>false</stop_on_fail></run_per_host>');
++$exptasklist_defaults['put'] = new SimpleXMLElement('<put 
name=""><source></source><destination></destination><stop_on_fail>false</stop_on_fail></put>');
++$exptasklist_defaults['get'] = new SimpleXMLElement('<get 
name=""><source></source><destination>./</destination><stop_on_fail>false</stop_on_fail></get>
 ');
++
++function exptasklist_addall()
++{
++    $sql = "SELECT * FROM exp_tasklist";
++    $indb = DBfetchArrayAssoc(DBSelect($sql), 'fsname');
++    
++    $indir = scandir($GLOBALS['GPLMT_TASKLISTS_DIR']);
++    
++    foreach($indir as $i)
++    {
++        if(substr($i, -4) != '.xml') continue;
++        if(isset($indb[$i])) continue;
++        $name = str_replace('_', ' ', $i);
++        $name = str_replace('.xml', '', $name);
++        
++        expdb_insert('exp_tasklist', array('name' => $name, 'fsname' => $i, 
'userid' => CWebUser::$data['userid'], 'shared' => 1));
++    }
++}
++
++function exptasklist_getall($editable = false)
++{
++    $sql = "SELECT exp_tasklist.*, CONCAT_WS(' ', users.name, users.surname) 
as username
++            FROM exp_tasklist INNER JOIN users ON exp_tasklist.userid = 
users.userid";
++    if(!(CWebUser::$data['type'] == 3)) //not super admin
++    {
++        $sql .= ' WHERE exp_tasklist.userid = '.CWebUser::$data['userid'];
++        if(!$editable)
++            $sql .= ' OR exp_tasklist.shared = 1';
++    }
++    
++    return DBfetchArray(DBselect($sql));
++}
++
++function exptasklist_getbyid($tasklistid)
++{
++    $res = expdb_select('exp_tasklist', array('tasklistid' => $tasklistid));
++    if(count($res) == 0) return null;
++    return $res[0];
++}
++
++function exptasklist_getcontent($tasklistid)
++{
++    $tl_row = exptasklist_getbyid($tasklistid);
++    if(!$tl_row) return null;
++    $file = $GLOBALS['GPLMT_TASKLISTS_DIR'].$tl_row['fsname'];
++    if(!file_exists($file)) return null;
++    return file_get_contents($file);
++}
++
++/**
++ * Given a tasklist id, returns 0, 1 or 2 for No access, read, read/write 
respectively
++ *
++ * @return int
++ */
++function exptasklist_allowed($tasklistid)
++{
++    $tl_row = exptasklist_getbyid($tasklistid);
++    if(!$tl_row) return 0;
++    if(CWebUser::$data['type'] == 3 || $tl_row['userid'] == 
CWebUser::$data['userid']) return 2;
++    if($tl_row['shared']) return 1;
++    return 0;
++}
++
++function exptasklist_delete($tid)
++{
++    $meta = exptasklist_getbyid($tid);
++    if(!$meta)
++    {
++        error("Invalid tasklist ID");
++        return false;
++    }
++    $fullFileName = $GLOBALS['GPLMT_TASKLISTS_DIR'].$meta['fsname'];
++    
++    //delete from DB
++    expdb_delete('exp_tasklist', array('tasklistid' => $tid));
++    
++    //delete file
++    if(file_exists($fullFileName)) unlink($fullFileName);
++    
++    return true;
++}
++
++function exptasklist_sxmlappend(SimpleXMLElement $to, SimpleXMLElement $from)
++{
++    $toDom = dom_import_simplexml($to);
++    $fromDom = dom_import_simplexml($from);
++    $newDom = $toDom->appendChild($toDom->ownerDocument->importNode($fromDom, 
true));
++    return simplexml_import_dom($newDom);
++}
++
++function exptasklist_constructxml($data)
++{
++    global $exptasklist_defaults;
++    
++    $xml = new SimpleXMLElement('<?xml version="1.0" 
encoding="UTF-8"?><tasklist></tasklist>');
++    $xml->addAttribute('xsi:noNamespaceSchemaLocation', 
"../tasklist_schema.xsd", "http://www.w3.org/2001/XMLSchema-instance";);
++    $xml->addChild('options');
++
++    //name
++    if(empty($data['name']))
++    {
++        error("Missing name field");
++        return false;
++    }
++    $name = $data['name'];
++    $xml->addAttribute('name', $name);
++    
++    //target
++    /*if(!empty($data['target']))
++        $xml->options->addChild('target', $data['target']);*/
++
++    //log dir
++    if(!empty($data['logdir']))
++        $xml->options->addChild('log_dir', $data['logdir']);
++    
++    //index for node components
++    $nodesIndex = array();
++    
++    foreach($data as $k => $v)
++    {
++        $parts = explode('_', $k); // field name consists of field type + the 
path to the field (e.g. command_2_1)
++        $parts_count = count($parts);
++        if($parts_count == 1 || $parts_count > 3) continue;
++        
++        $field = str_replace('$', '_', $parts[0]);
++        $value = trim($v);
++        $index = implode('_', array_slice($parts, 1));
++        
++        if($field == 'type') //should be the first field in the node, its type
++        {
++            if(!array_key_exists($value, $exptasklist_defaults)) continue; 
//invalid type
++            
++            if($parts_count == 2) $parent = $xml;
++            else $parent = $nodesIndex[$parts[1]];
++            
++            $newXml = $exptasklist_defaults[$value];
++            if($value != 'sequence')
++            {
++                $newXml['id'] = $parts[$parts_count - 1]; //GPLMT doesn't 
accept ID in sequence but mandatory for others
++                $newXml['name'] = $newXml['id']; //Name is also mandatory, so 
we set it by the ID unless we get a name from the user later
++            }
++            $newXml['enabled'] = 'false'; //Disabled by default unless we get 
the enabled flag from form
++            
++            $nodesIndex[$index] = exptasklist_sxmlappend($parent, $newXml);
++            
++            
++            continue;
++        }
++        
++        if(!array_key_exists($index, $nodesIndex)) continue; //problem or 
data element that is not related to the XML
++        if($field == 'name' && empty($value)) continue;
++        
++        $subxml = $nodesIndex[$index];
++        $type = $subxml->getName();
++        
++        //validations:
++        switch($field)
++        {
++            //bool
++            case 'enabled': case 'stop_on_fail':
++                $value = strtolower($value);
++                if($value != 'yes' && $value != 'no')
++                {
++                    error("Value for $field should be true or false!");
++                    return false;
++                }
++                $value = ($value == 'yes') ? 'true' : 'false';
++                break;
++            
++            //int
++            case 'timeout': case 'expected_return_code':
++                if(!is_numeric($value))
++                {
++                    error("Value for $field should be an integer!");
++                    return false;
++                }
++                break;
++
++            //file
++            case 'source':
++                if($type == 'put')
++                {
++                    $value = exp_cleanfilename($value);
++                }
++                break;
++            case 'destination':
++                if($type == 'get')
++                {
++                    $value = './';
++                }
++                break;
++        }
++        
++        //writing values
++        switch($field)
++        {
++            //attributes
++            case 'enabled': case 'name':
++                $subxml[$field] = $value;
++                break;
++            
++            case 'command': case 'arguments': case 'timeout': case 
'expected_return_code': case 'expected_output':
++            case 'stop_on_fail': case 'command_file': case 'output_prefix': 
case 'source': case 'destination':
++                $subxml->$field = $value;
++                break;
++            
++            default:
++                error("Unknown field: $field");
++        }
++    }
++    
++    //save the resulting XML to file (formatted)
++    $dom = dom_import_simplexml($xml)->ownerDocument;
++    $dom->formatOutput = true;
++    return $dom->saveXML();
++}
++
++function exptasklist_add($data)
++{
++    $xml = exptasklist_constructxml($data);
++    if(!$xml) return false;
++    
++    //name
++    $name = $data['name'];
++    
++    //description
++    $description = empty($data['description']) ? '' : $data['description'];
++    
++    //shared
++    $shared = false;
++    $shared = (!empty($data['shared']) && ($data['shared'] == 'yes'));
++    
++    //create new fsname
++    $fsname = str_replace(' ', '_', $name);
++    $fsname = str_replace('\\', '_', $fsname);
++    $counter = 0;
++    while(file_exists($GLOBALS['GPLMT_TASKLISTS_DIR'].$fsname.'.xml'))
++    {
++        $fsname .= strval($counter);
++        $counter++;
++    }
++    $fsname .= '.xml';
++    
++    //user ID
++    $userid = CWebUser::$data['userid'];
++    
++    //save to file
++    file_put_contents($GLOBALS['GPLMT_TASKLISTS_DIR'].$fsname, $xml);
++    
++    //save to DB
++    expdb_insert('exp_tasklist',
++        array('name' => $name, 'description' => $description, 'fsname' => 
$fsname, 'userid' => $userid, 'shared' => intval($shared)));
++    
++    return true;
++}
++
++function exptasklist_update($tasklistid, $data)
++{
++    $meta = exptasklist_getbyid($tasklistid); //get task meta data from db
++    
++    $xml = exptasklist_constructxml($data);
++    if(!$xml) return false;
++    
++    //name
++    $name = $data['name'];
++    
++    //description
++    $description = empty($data['description']) ? '' : $data['description'];
++    
++    //shared
++    $shared = false;
++    $shared = (!empty($data['shared']) && ($data['shared'] == 'yes'));
++    
++    file_put_contents($GLOBALS['GPLMT_TASKLISTS_DIR'].$meta['fsname'], $xml);
++    
++    //update DB
++    expdb_update('exp_tasklist', array('name' => $name, 'description' => 
$description, 'shared' => intval($shared)),
++        array('tasklistid' => $tasklistid));
++    
++    return true;
++}
+diff --git include/menu.inc.php include/menu.inc.php
+index 6e27065..51b0d56 100644
+--- include/menu.inc.php
++++ include/menu.inc.php
+@@ -281,6 +281,38 @@ $ZBX_MENU = array(
+                       )
+               )
+       ),
++      'experiment' => array(
++              'label'                         => _('Experiments'),
++              'user_type'                     => USER_TYPE_ZABBIX_ADMIN,
++              'node_perm'                     => PERM_READ_WRITE,
++              'default_page_id'       => 0,
++              'pages' => array(
++                      array(
++                              'url' => 'execute.php',
++                              'label' => _('Deploy & Execute')
++                      ),
++                      array(
++                              'url' => 'results.php',
++                              'label' => _('Results')
++                      ),
++                      array(
++                              'url' => 'targets.php',
++                              'label' => _('Targets')
++                      ),
++                      array(
++                              'url' => 'tasklist.php',
++                              'label' => _('Tasklists')
++                      ),
++                      array(
++                              'url' => 'files.php',
++                              'label' => _('Files')
++                      ),
++                      array(
++                              'url' => 'conf.php',
++                              'label' => _('Configuration')
++                      )
++              )
++      ),
+       'login' => array(
+               'label'                                 => _('Login'),
+               'user_type'                             => 0,
+diff --git include/views/administration.script.list.php 
include/views/administration.script.list.php
+index bb42f3f..aab1244 100644
+--- include/views/administration.script.list.php
++++ include/views/administration.script.list.php
+@@ -40,9 +40,18 @@ $scriptsTable->setHeader(array(
+       make_sorting_header(_('Commands'), 'command'),
+       _('User group'),
+       _('Host group'),
+-      _('Host access')
++      _('Host access'),
++      _('Run on Host Group')
+ ));
+ 
++//get list of host groups
++$hostgroups = API::HostGroup()->get(array(
++              'not_proxy_host' => 1,
++              'sortfield' => 'name',
++              'editable' => true,
++              'output' => array('name')
++      ));
++
+ foreach ($this->data['scripts'] as $script) {
+       $scriptid = $script['scriptid'];
+ 
+@@ -72,6 +81,18 @@ foreach ($this->data['scripts'] as $script) {
+               $scriptExecuteOn = '';
+       }
+ 
++    //create hostgroups combobox
++    $runForm = new CForm('GET', 'scripts_exec.php');
++    $runForm->addItem(new CInput('hidden', 'execute', '1'));
++    $runForm->addItem(new CInput('hidden', 'scriptid', $script['scriptid']));
++    
++    $grpsComboBox = new CComboBox('groupid');
++    foreach($hostgroups as $hostgroup)
++        $grpsComboBox->addItem(new CComboItem($hostgroup['groupid'], 
$hostgroup['name']));
++
++    $runForm->addItem($grpsComboBox);
++    $runForm->addItem(new CInput('submit', 'submit', 'Run'));
++
+       $scriptsTable->addRow(array(
+               new CCheckBox('scripts['.$script['scriptid'].']', 'no', null, 
$script['scriptid']),
+               new CLink($script['name'], 
'scripts.php?form=1&scriptid='.$script['scriptid']),
+@@ -80,7 +101,8 @@ foreach ($this->data['scripts'] as $script) {
+               zbx_nl2br(htmlspecialchars($script['command'], ENT_COMPAT, 
'UTF-8')),
+               ('' == $script['userGroupName']) ? _('All') : 
$script['userGroupName'],
+               ('' == $script['hostGroupName']) ? _('All') : 
$script['hostGroupName'],
+-              ((PERM_READ_WRITE == $script['host_access']) ? _('Write') : 
_('Read'))
++              ((PERM_READ_WRITE == $script['host_access']) ? _('Write') : 
_('Read')),
++              $runForm
+       ));
+ }
+ 
+diff --git include/views/experiments.conf.php 
include/views/experiments.conf.php
+new file mode 100644
+index 0000000..0af85d5
+--- /dev/null
++++ include/views/experiments.conf.php
+@@ -0,0 +1,66 @@
++<?php
++
++$conf = $this->get('conf');
++
++$cWidget = new CWidget();
++
++$cForm = new CForm('post');
++$cTable = new CTableInfo();
++
++$current_section = '';
++foreach($conf as $c)
++{
++    if($c['section'] != $current_section)
++    {
++        $current_section = $c['section'];
++        $cTable->addRow(strtoupper($current_section));
++    }
++    
++    switch($c['type'])
++    {
++        case 'text': case 'integer':
++            $cInput = new CTextBox($c['configid'], $c['value']);
++            break;
++        
++        case 'password':
++            $cInput = new CPassBox($c['configid'], $c['value'], 20);
++            break;
++        
++        case 'boolean':
++            $cHidden = new CInput('hidden', $c['configid'], 'no');
++            $cChkbox = new CCheckBox($c['configid'], $c['value']);
++            $cInput = array($cHidden, $cChkbox);
++            break;
++        
++        case 'file':
++            $userfiles = expfiles_getuserfiles();
++            $selectedfile = '';
++            if(!empty($c['value'])) $selectedfile = basename($c['value']);
++            $cInput = new CComboBox($c['configid']);
++            $cInput->addItem('', '');
++            foreach($userfiles as $uf)
++                $cInput->addItem($uf, $uf, ($selectedfile == $uf)?'yes':null);
++            break;
++
++        case 'enum':
++            $options = expconfig_getenum($c['configid']);
++            $cInput = new CComboBox($c['configid']);
++            foreach($options as $o)
++                $cInput->addItem($o['value'], $o['label'], ($c['value'] == 
$o['value'])?'yes':null);
++            break;
++
++        default:
++            $cInput = new CLabel('Invalid type');
++            break;
++    }
++    
++    $help_image = new CImg('images/general/question_mark.png');
++    $help_image->attr('title', $c['description']);
++    
++    $cTable->addRow(array($c['label'], array($cInput, $help_image)));
++}
++$cTable->addRow(new CSubmit('update', 'Update'));
++
++$cForm->addItem($cTable);
++$cWidget->addItem($cForm);
++return $cWidget;
+diff --git include/views/experiments.execute.php 
include/views/experiments.execute.php
+new file mode 100644
+index 0000000..bc87ce3
+--- /dev/null
++++ include/views/experiments.execute.php
+@@ -0,0 +1,100 @@
++<?php
++
++$targets = $this->get('targets');
++$currenttarget = $this->get('currenttarget');
++
++//Main Form
++$exec_frm = new CForm();
++$exec_frm->setName('web.experiment.execute.php.');
++$exec_frm->attr('id', 'mainfrm');
++
++//Main table
++$main_table = new CTable();
++
++//Row 1 - Targets
++$targets_cmb = new CComboBox('target');
++foreach($targets as $k => $v)
++    $targets_cmb->addItem($v, $k, ($v == $currenttarget)?'yes':null);
++$targets_cmb->attr('onchange', "jQuery('#mainfrm').submit();");
++
++$main_table->addRow(new CRow(array(
++    'Select Target:',
++    $targets_cmb)));
++
++//Row 2 - Target settings
++$settings_enabled = false;
++switch($currenttarget)
++{
++    case 'ssh':
++        $settings_enabled = true;
++        
++        $sshhosts = expnodes_gethosts('ssh');
++        $sshhosts_tb = new CTweenBox($exec_frm, 'hosts');
++        foreach($sshhosts as $sh)
++            $sshhosts_tb->addItem($sh['hostid'], $sh['host'], true);
++        
++        $settings_elm = $sshhosts_tb->get('Selected:', 'Excluded:');
++        
++        break;
++    
++    case 'planetlab':
++        $settings_enabled = true;
++        
++        $plhosts = exppl_getSliceNodes();
++        $plhosts_tb = new CTweenBox($exec_frm, 'hosts');
++        foreach($plhosts as $ph)
++            $plhosts_tb->addItem($ph['hostid'], $ph['hostname'], true);
++        
++        $settings_elm = $plhosts_tb->get('Selected:', 'Excluded:');
++    
++        break;
++    
++    default:
++        $settings_enabled = true;
++        $settings_elm = 'Invalid Target. WHY?';
++        break;
++}
++if($settings_enabled)
++    $main_table->addRow(new CRow(array(
++        'Target Settings:',
++        $settings_elm)));
++
++//Row 3 - Tasklists
++$tasklists = $this->get('tasklists');
++
++$tasklists_tbl = new CTable();
++
++$tasklists_rad1 = new CRadioButton('usetasklist', '1', 'input radio', null, 
true);
++$tasklists_rad2 = new CRadioButton('usetasklist', '0', 'input radio');
++$tasklists_cmb = new CComboBox('tasklist');
++foreach($tasklists as $t)
++    $tasklists_cmb->addItem($t['tasklistid'], $t['name']);
++$tasklists_txt = new CTextBox('cmd');
++
++
++$tasklists_tbl->addRow(
++array(
++new CDiv(array(
++$tasklists_rad1, 'Tasklist:')),
++$tasklists_cmb));
++$tasklists_tbl->addRow(
++array(
++new CDiv(array(
++$tasklists_rad2, 'Command:')),
++$tasklists_txt));
++
++$main_table->addRow(new CRow(array(
++    'Select Tasklist / Command:',
++    $tasklists_tbl
++)));
++
++
++$exec_frm->addItem($main_table);
++
++/*
++ * footer
++ */
++$run_submit = array(new CSubmit('run', 'Run'));
++$exec_frm->addItem(makeFormFooter($run_submit));
++
++return $exec_frm;
+diff --git include/views/experiments.files.php 
include/views/experiments.files.php
+new file mode 100644
+index 0000000..1fd1203
+--- /dev/null
++++ include/views/experiments.files.php
+@@ -0,0 +1,30 @@
++<?php
++
++$files = $this->get('files');
++
++$fWidget = new CWidget();
++
++$uploadForm = new CForm('post', null, 'multipart/form-data');
++$uploadForm->addItem(new CInput('file', 'file'));
++$uploadForm->addItem(new CSubmit('upload', 'Upload file'));
++//add maximum size note
++
++$fWidget->addPageHeader('USER FILES', $uploadForm);
++
++$files_tbl = new CTableInfo('No files added yet.');
++$files_tbl->setHeader(array('File name', ''));
++foreach($files as $f)
++{
++    //download link
++    $download_lnk = new CLink($f, '?download='.$f);
++    
++    //delete link
++    $delete_lnk = new CLink('delete', '?delete='.$f);
++    
++    $files_tbl->addRow(array($download_lnk, $delete_lnk));
++    //TODO: add delete, download
++}
++
++$fWidget->addItem($files_tbl);
++
++return $fWidget;
+diff --git include/views/experiments.results.php 
include/views/experiments.results.php
+new file mode 100644
+index 0000000..2591b41
+--- /dev/null
++++ include/views/experiments.results.php
+@@ -0,0 +1,63 @@
++<?php
++
++//Main table
++$main_table = new CTableInfo();
++
++$results = $this->get('results');
++$runid = $this->get('runid'); //if set, one of the runs is selected
++
++$main_table->setHeader(array('', 'Status', 'Started On', 'Target', 
'Percentage completed', '', ''));
++
++foreach($results as $r)
++{
++    $div_actions = new CDiv();
++    if($r['status'] == 'Running')
++        $div_actions->addItem(new CLink('interrupt', 
'results.php?interrupt='.$r['runid']));
++    else
++    {
++        $div_actions->addItem(new CLink('delete', 
'results.php?delete='.$r['runid']));
++        //$div_actions->addItem(new CButtonDelete('Are you sure you want to 
delete?', $r['runid']));
++        $div_actions->addItem(' | ');
++        $div_actions->addItem(new CLink('re-run', 
'results.php?rerun='.$r['runid']));
++    }
++    
++    //nodes table
++    $nodes_table = new CTableInfo();
++    foreach($r['nodes'] as $n)
++    {
++        $nodes_table->addRow(new CRow(array(
++            $n['interface'],
++            $n['status'],
++            $n['percentage'].'%',
++            new CLink('log', 
'results.php?runid='.$r['runid'].'&hostid='.$n['hostid'])
++        )));
++    }
++    
++    $main_row = array(
++        new CButton(null, '+/-', 
"javascript:jQuery('#".$r['runid']."').toggle();"),
++        $r['status'],
++        $r['startedon'],
++        $r['target'],
++        $r['percentage'].'%',
++        new CLink('log', 'results.php?runid='.$r['runid']),
++        $div_actions
++        );
++    $main_table->addRow(new CRow($main_row));
++    $hidden_col = new CCol($nodes_table, null, count($main_row));
++    $hidden_col->attr('id', $r['runid']);
++    if(empty($runid) || $runid != $r['runid'])
++        $hidden_col->attr('style', 'display:none;');
++    $main_table->addRow(new CRow($hidden_col));
++}
++
++$log = $this->get('log');
++
++if(!empty($log))
++{
++    $res_txt = new CTextArea(null, $log, array('rows' => substr_count($log, 
"\n") + 1, 'readonly' => 1));
++    $res_txt->attr('style', 'width:100%;font-size:15px;');
++    
++    return new CDiv(array($main_table, 'RESULT:', $res_txt));
++}
++else
++    return $main_table;
+diff --git include/views/experiments.targets.php 
include/views/experiments.targets.php
+new file mode 100644
+index 0000000..af46fba
+--- /dev/null
++++ include/views/experiments.targets.php
+@@ -0,0 +1,90 @@
++<?php
++$targetlist = $this->get('targetlist');
++$default_target = reset($targetlist);
++$selected_target = $this->get('selected_target');
++if(!$selected_target) $selected_target = $default_target;
++
++//Main form
++$main_frm = new CForm();
++$main_frm->setName('web.experiment.targets.php.');
++$main_frm->attr('id', 'mainfrm');
++
++//Main table
++$main_table = new CTable();
++
++//Row 1 - Targets
++$targets_cmb = new CComboBox('target');
++foreach($targetlist as $k => $v)
++    $targets_cmb->addItem($v, $k, ($v == $selected_target)?'yes':null);
++$targets_cmb->attr('onchange', "jQuery('#mainfrm').submit();");
++$main_table->addRow(array('Target:', $targets_cmb));
++
++//Row 2 - Target edit
++switch($selected_target)
++{
++    case 'ssh':
++        $ssh_lst = new CListBox('sshhosts[]', null, 12);
++        $sshhosts = $this->get('sshhosts');
++        foreach($sshhosts as $sh)
++            $ssh_lst->addItem($sh['hostid'], $sh['host']);
++        
++        $del_btn = new CButton('delsshhost', 'Remove', 
"jQuery('select[name=\"sshhosts[]\"]').find(':selected').remove()");
++        
++        $add_txt = new CTextBox('newsshhost', null, 30);
++        $add_btn =  new CButton('addsshhost', 'Add', 
"jQuery('select[name=\"sshhosts[]\"]').append('<option>'+jQuery('input[name=newsshhost]').val()+'</option>');jQuery('input[name=newsshhost]').val('')");
++        
++        $submit_btn = new CSubmit('apply', 'Apply');
++        $submit_btn->attr('onclick', "jQuery('select[name=\"sshhosts[]\"] 
option').attr('selected', 'yes')");
++        
++        $main_table->addRow(array('SSH:', array($ssh_lst, $del_btn)));
++        $main_table->addRow(array('', array($add_txt, $add_btn)));
++        $main_table->addRow(array('', $submit_btn));
++        
++        break;
++    
++    case 'planetlab':
++        $pagesize = 20;
++        $pageoffset = intval($this->get('ploffset'));
++        if(!$pageoffset || $pageoffset < 0) $pageoffset = 0;
++        $hostfilter = $this->get('plfilter');
++        if(!$hostfilter) $hostfilter = null;
++        $slicename = exppl_getslicename();
++        $slicenodes = exppl_getSliceNodes();
++        $availnodes = exppl_getAvailableNodes($pageoffset, $pagesize, 
$hostfilter);
++    
++        $pl_tb = new CTweenBox($main_frm, 'plnodes');
++        foreach($slicenodes as $sn)
++            $pl_tb->addItem($sn['node_id'], $sn['hostname'], true);
++        foreach($availnodes as $an)
++            $pl_tb->addItem($an['node_id'], $an['hostname']);
++        
++        $filter_frm = new CForm('get');
++        $filter_frm->attr('id', 'filterfrm');
++        $filter_tb = new CTextBox('plfilter', $hostfilter);
++        $filter_tb->attr('id', 'plfilter');
++        $filter_btn = new CSubmit('filter', 'Filter', 
'jQuery("#ploffset").val(0)');
++        $page_tb = new CTextBox('ploffset', $pageoffset, 2);
++        $page_tb->attr('id', 'ploffset');
++        $prev_btn = new CSubmit('plprev', '<<', 
'jQuery("#ploffset").val(parseInt(jQuery("#ploffset").val(), 10) - 
1);jQuery("#filterfrm").submit();');
++        $next_btn = new CSubmit('plnext', '>>', 
'jQuery("#ploffset").val(parseInt(jQuery("#ploffset").val(), 10) + 
1);jQuery("#filterfrm").submit();');
++        $clear_btn = new CSubmit('plclear', 'Clear', 
'jQuery("#ploffset").val(0);jQuery("#plfilter").val("")');
++        $filter_tbl = new CTable();
++        $filter_tbl->addRow(array(array($prev_btn, $page_tb, $next_btn)));
++        $filter_tbl->addRow(array(array('Filter:', $filter_tb, $filter_btn)));
++        $filter_tbl->addRow(array($clear_btn));
++        $filter_frm->addItem($filter_tbl);
++        
++        $pl_tbl = new CTable();
++        $pl_tbl->addRow(array($pl_tb->get($slicename, 'Available'), 
$filter_frm));
++        
++        $submit_btn = new CSubmit('apply', 'Apply');
++        
++        $main_table->addRow(array('Planetlab', $pl_tbl));
++        $main_table->addRow(array('', $submit_btn));
++        
++        break;
++}
++
++$main_frm->addItem($main_table);
++
++return $main_frm;
+diff --git include/views/experiments.tasklist.edit.php 
include/views/experiments.tasklist.edit.php
+new file mode 100644
+index 0000000..152cf29
+--- /dev/null
++++ include/views/experiments.tasklist.edit.php
+@@ -0,0 +1,318 @@
++<?php
++
++$new = $this->get('new');
++
++if($new)
++    $xml = new SimpleXMLElement('<?xml version="1.0" 
encoding="UTF-8"?><tasklist></tasklist>');
++else
++    $xml = $this->get('xml');
++
++//$targets = $this->get('targets');
++$tid = $this->get('tid');
++if($new)
++    $meta = array();
++else
++    $meta = $this->get('meta');
++$exptasklist_defaults = $this->get('exptasklist_defaults');
++
++function tlview_parseseq($xml, $postfix)
++{
++    $seq_tbl = new CTableInfo('');
++    $seq_tbl->attr('id', "table$postfix");
++    
++    //Top Row:
++    $btns_div = new CDiv();
++    //Delete button
++    $del_btn = new CButton('delete', 'delete', 'javascript: 
jQuery("#row'.$postfix.'").remove()');
++    //Type (hidden)
++    $type_hdn = new CInput('hidden', 'type'.$postfix, 'sequence');
++    $btns_div->addItem($type_hdn);
++    //Add runs
++    $run_cmb = new CComboBox('run');
++    $run_cmb->attr('id', "runs$postfix");
++    $run_cmb->addItem('run', 'run');
++    $run_cmb->addItem('run_per_host', 'run_per_host');
++    $run_cmb->addItem('put', 'put');
++    $run_cmb->addItem('get', 'get');
++    $btns_div->addItem($run_cmb);
++    $js = 'javascript: '; //javascript used to add runs under this sequence
++    $js .= 'if (typeof window.counter'.$postfix.' === "undefined") 
window.counter'.$postfix.' = '.(count($xml->children())+1).';';
++    $js .= 'new_node(jQuery("#runs'.$postfix.'").val(), 
"'.$postfix.'_"+counter'.$postfix.', "table'.$postfix.'", 
counter'.$postfix.'%2);';
++    $js .= 'counter'.$postfix.'++;';
++    $add_btn = new CButton('add', 'Add', $js);
++    $btns_div->addItem($add_btn);
++    //Move up
++    $mvup_btn = new CButton('mvup', 'Move UP', 'javascript: 
p=jQuery("#row'.$postfix.'").prev(); if(p.attr("id")) 
jQuery("#row'.$postfix.'").insertBefore(p);');
++    $btns_div->addItem($mvup_btn);
++    //Move down
++    $mvdown_btn = new CButton('mvdown', 'Move DOWN', 'javascript: 
n=jQuery("#row'.$postfix.'").next(); if(n.attr("id")) 
jQuery("#row'.$postfix.'").insertAfter(n);');
++    $btns_div->addItem($mvdown_btn);
++    
++    $seq_tbl->addRow(array($del_btn, $btns_div));
++    
++    //Sequence attributes
++    
++    //Name attribute
++    $name_tb = new CInput('text', 'name'.$postfix, (string)$xml['name']);
++    $name_tb->addStyle('width: 50em;');
++    $seq_tbl->addRow(array('Name:', $name_tb));
++    
++    //Enabled attribute
++    $enabled_chb = new CCheckBox('enabled'.$postfix, 
(((string)$xml['enabled']) == 'false')?'no':'yes');
++    $seq_tbl->addRow(array('Enabled:', $enabled_chb));
++    
++    
++    $counter = 1;
++    foreach($xml->children() as $c)
++    {
++        $name = trim($c->getName());
++        $row_postfix = $postfix.'_'.$counter;
++        $seq_tbl->addRow(tlview_parserun($name, $c, $row_postfix));
++        $counter++;
++    }
++    
++    //print "<script>var counter$postfix = $counter</script>";
++    
++    return new CRow(array('Sequence:', $seq_tbl), null, "row$postfix");
++}
++function tlview_parserun($type, $xml, $postfix)
++{
++    $run_tbl = new CTableInfo('');
++    
++    //common elements
++    
++    //Top Row:
++    $btns_div = new CDiv();
++    //Delete button
++    $del_btn = new CButton('delete', 'delete', 'javascript: 
jQuery("#row'.$postfix.'").remove()');
++    //Type (hidden)
++    $type_hdn = new CInput('hidden', 'type'.$postfix, $type);
++    $btns_div->addItem($type_hdn);
++    //Move up
++    $mvup_btn = new CButton('mvup', 'Move UP', 'javascript: 
p=jQuery("#row'.$postfix.'").prev(); if(p.attr("id")) 
jQuery("#row'.$postfix.'").insertBefore(p);');
++    $btns_div->addItem($mvup_btn);
++    //Move down
++    $mvdown_btn = new CButton('mvdown', 'Move DOWN', 'javascript: 
n=jQuery("#row'.$postfix.'").next(); if(n.attr("id")) 
jQuery("#row'.$postfix.'").insertAfter(n);');
++    $btns_div->addItem($mvdown_btn);
++    
++    $run_tbl->addRow(array($del_btn, $btns_div));
++    
++    //Name attribute
++    $name_tb = new CInput('text', 'name'.$postfix, (string)$xml['name']);
++    $name_tb->addStyle('width: 50em;');
++    $run_tbl->addRow(array('Name:', $name_tb));
++    
++    //Enabled attribute
++    $enabled_chb = new CCheckBox('enabled'.$postfix, 
(((string)$xml['enabled']) == 'false')?'no':'yes');
++    $run_tbl->addRow(array('Enabled:', $enabled_chb));
++    
++    switch($type)
++    {
++        case 'run':
++            //command
++            $cmd_tb = new CInput('text', 'command'.$postfix, 
(string)$xml->command);
++            $cmd_tb->addStyle('width: 50em;');
++            $run_tbl->addRow(array('Command:', $cmd_tb));
++            
++            //arguments
++            $args_tb = new CInput('text', 'arguments'.$postfix, 
(string)$xml->arguments);
++            $args_tb->addStyle('width: 50em;');
++            $run_tbl->addRow(array('Arguments:', $args_tb));
++            
++            //timeout
++            $timeout_tb = new CInput('text', 'timeout'.$postfix, 
(string)$xml->timeout);
++            $run_tbl->addRow(array('Timeout:', $timeout_tb));
++            
++            //expected_return_code
++            $expected_return_code_tb = new CInput('text', 
'expected$return$code'.$postfix, (string)$xml->expected_return_code);
++            $run_tbl->addRow(array('Expected Return Code:', 
$expected_return_code_tb));
++            
++            //expected_output
++            $expected_output_tb = new CInput('text', 
'expected$output'.$postfix, (string)$xml->expected_output);
++            $expected_output_tb->addStyle('width: 50em;');
++            $run_tbl->addRow(array('Expected Output:', $expected_output_tb));
++            
++            break;
++        case 'run_per_host':
++            //command_file
++            $command_file_tb = new CInput('text', 'command$file'.$postfix, 
(string)$xml->command_file);
++            $command_file_tb->addStyle('width: 50em;');
++            $run_tbl->addRow(array('Command File:', $command_file_tb));
++            
++            //output_prefix
++            $output_prefix_tb = new CInput('text', 'output$prefix'.$postfix, 
(string)$xml->output_prefix);
++            $output_prefix_tb->addStyle('width: 50em;');
++            $run_tbl->addRow(array('Output Prefix:', $output_prefix_tb));
++            
++            //timeout
++            $timeout_tb = new CInput('text', 'timeout'.$postfix, 
(string)$xml->timeout);
++            $run_tbl->addRow(array('Timeout:', $timeout_tb));
++            
++            //expected_return_code
++            $expected_return_code_tb = new CInput('text', 
'expected$return$code'.$postfix, (string)$xml->expected_return_code);
++            $run_tbl->addRow(array('Expected Return Code:', 
$expected_return_code_tb));
++            
++            //expected_output
++            $expected_output_tb = new CInput('text', 
'expected$output'.$postfix, (string)$xml->expected_output);
++            $expected_output_tb->addStyle('width: 50em;');
++            $run_tbl->addRow(array('Expected Output:', $expected_output_tb));
++        
++            break;
++        case 'put':
++            //source
++            $userfiles = expfiles_getuserfiles();
++            $selectedfile = '';
++            if(!empty($xml->source)) $selectedfile = 
basename((string)$xml->source);
++            $source_cmb = new CComboBox('source'.$postfix);
++            foreach($userfiles as $uf)
++                $source_cmb->addItem($uf, $uf, ($selectedfile == 
$uf)?'yes':null);
++            $run_tbl->addRow(array('Source:', $source_cmb));
++            
++            //destination
++            $destination_tb = new CInput('text', 'destination'.$postfix, 
(string)$xml->destination);
++            $destination_tb->addStyle('width: 50em;');
++            $run_tbl->addRow(array('Destination:', $destination_tb));
++        
++            break;
++        case 'get':
++            //source
++            $source_tb = new CInput('text', 'source'.$postfix, 
(string)$xml->source);
++            $source_tb->addStyle('width: 50em;');
++            $run_tbl->addRow(array('Source:', $source_tb));
++            
++            //destination (removed because now all files should go to the 
user specific folder)
++            /*$destination_tb = new CInput('text', 'destination'.$postfix, 
(string)$xml->destination);
++            $destination_tb->addStyle('width: 50em;');
++            $run_tbl->addRow(array('Destination:', $destination_tb));*/
++            break;
++    }
++    
++    //Stop on fail
++    $stop_on_fail_chb = new CCheckBox('stop$on$fail'.$postfix, 
(((string)$xml->stop_on_fail) == 'false')?'no':'yes');
++    $run_tbl->addRow(array('Stop on fail:', $stop_on_fail_chb));
++    
++    return new CRow(array("$type:", $run_tbl), null, "row$postfix");
++    return $run_tbl;
++}
++
++//print_r($xml);
++
++if($new)
++    $main_frm = new CForm('post', 'tasklist.php?new=new');
++else
++    $main_frm = new CForm('post', 'tasklist.php?tid='.$tid);
++$main_tbl = new CTableInfo('');
++$main_tbl->attr('id', 'table_main');
++
++//Top Row:
++$btns_div = new CDiv();
++//'Add run' (all types)
++$run_cmb = new CComboBox('run');
++$run_cmb->attr('id', 'runs_main');
++$run_cmb->addItem('sequence', 'sequence');
++$run_cmb->addItem('run', 'run');
++$run_cmb->addItem('run_per_host', 'run_per_host');
++$run_cmb->addItem('put', 'put');
++$run_cmb->addItem('get', 'get');
++$btns_div->addItem($run_cmb);
++$add_btn = new CButton('add', 'Add', "javascript: 
new_node(jQuery('#runs_main').val(), '_'+counter, 'table_main', counter%2); 
counter++;");
++$btns_div->addItem($add_btn);
++
++$main_tbl->addRow(array('', $btns_div));
++
++//name attribute
++$name_tb = new CInput('text', 'name', (string)$xml['name']);
++$name_tb->addStyle('width: 50em;');
++$main_tbl->addRow(array('Name:', $name_tb));
++
++//description
++$desc_ta = new CTextArea('description', 
(empty($meta['description']))?'':$meta['description']);
++$main_tbl->addRow(array('Description:', $desc_ta));
++
++//shared
++$shared_chb = new CCheckBox('shared', (empty($meta['shared']))?'no':'yes');
++$main_tbl->addRow(array('Shared:', $shared_chb));
++
++//option 1 - Target
++/*$selected_target = 
isset($xml->options->target)?trim((string)$xml->options->target):'remote_ssh';
++$target_cmb = new CComboBox('target');
++foreach($targets as $t)
++    $target_cmb->addItem($t, $t, ($selected_target == $t)?'yes':null);
++$main_tbl->addRow(array('Target:', $target_cmb));*/
++
++//option 2 - Log dir
++$log_dir = 
isset($xml->options->log_dir)?trim((string)$xml->options->log_dir):'';
++$log_dir_tb = new CInput('text', 'log$dir', $log_dir);
++$log_dir_tb->addStyle('width: 50em;');
++$main_tbl->addRow(array('Log Dir:', $log_dir_tb));
++
++$counter = 1;
++foreach($xml->children() as $c)
++{
++    $name = trim($c->getName());
++    if($name == 'sequence')
++    {
++        $main_tbl->addRow(tlview_parseseq($c, '_'.$counter));
++        $counter++;
++    }
++    elseif($name == 'run' || $name == 'run_per_host' || $name == 'put' || 
$name == 'get')
++    {
++        $main_tbl->addRow(tlview_parserun($name, $c, '_'.$counter));
++        $counter++;
++    }
++}
++
++$main_frm->addItem($main_tbl);
++
++//$main_frm->addItem(new CInput('hidden', 'tid', $tid));
++if($new)
++    $main_frm->addItem(new CSubmit('add', 'Add'));
++else
++    $main_frm->addItem(new CSubmit('update', 'Update'));
++
++/*print "TESTING:<br/>";
++$tmp = tlview_parserun('run', $default_run, '_100');
++print $tmp->toString();
++print "END TESTING";*/
++
++
++?>
++
++<script>
++var counter = <?=$counter?>;
++
++function new_node(type, postfix, table_id, parity)
++{
++var html = '';
++switch(type)
++{
++case 'sequence':
++html = '<?php print tlview_parseseq($exptasklist_defaults["sequence"], 
"%placeholder%"); ?>';
++break;
++case 'run':
++html = '<?php print tlview_parserun("run", $exptasklist_defaults["run"], 
"%placeholder%"); ?>';
++break;
++case 'run_per_host':
++html = '<?php print tlview_parserun("run_per_host", 
$exptasklist_defaults["run_per_host"], "%placeholder%"); ?>';
++break;
++case 'put':
++html = '<?php print tlview_parserun("put", $exptasklist_defaults["put"], 
"%placeholder%"); ?>';
++break;
++case 'get':
++html = '<?php print tlview_parserun("get", $exptasklist_defaults["get"], 
"%placeholder%"); ?>';
++break;
++}
++
++html = html.replace(/%placeholder%/g, postfix);
++jQuery('#'+table_id).append(html);
++var cl = (parity == 0)?'even_row':'odd_row';
++jQuery('#row'+postfix).addClass(cl);
++jQuery('#row'+postfix).attr('origclass', cl);
++jQuery('#name'+postfix).focus();
++}
++
++</script>
++
++<?php
++
++return $main_frm;
+diff --git include/views/experiments.tasklist.php 
include/views/experiments.tasklist.php
+new file mode 100644
+index 0000000..e6e0ed8
+--- /dev/null
++++ include/views/experiments.tasklist.php
+@@ -0,0 +1,41 @@
++<?php
++
++$tasklists = $this->get('tasklists');
++
++$tlWidget = new CWidget();
++
++$createForm = new CForm('get');
++$createForm->addItem(new CSubmit('new', 'Create tasklist'));
++
++$tlWidget->addPageHeader('CONFIGURATION OF TASKLISTS', $createForm);
++
++//main form
++$tlForm = new CForm('get');
++$tlForm->setName('tasklistForm');
++
++//main table
++$tlTable = new CTableInfo('No tasklists defined.');
++$tlTable->setHeader(array('Name', 'Description', 'User', 'Shared', ''));
++
++foreach($tasklists as $tl)
++{
++    //Name link
++    $name_lnk = new CLink($tl['name'], '?tid='.$tl['tasklistid']);
++    
++    //Delete link
++    $del_btn = new CButtonDelete('Are you sure you want to delete this 
tasklist?', $tl['tasklistid']);
++    
++    $tlTable->addRow(array(
++        $name_lnk,
++        ($tl['description'])?$tl['description']:'',
++        $tl['username'],
++        ($tl['shared'])?'Yes':'No',
++        $del_btn
++        ));
++}
++
++$tlForm->addItem($tlTable);
++
++$tlWidget->addItem($tlForm);
++
++return $tlWidget;
+diff --git include/views/general.script.execute-parallel.php 
include/views/general.script.execute-parallel.php
+new file mode 100644
+index 0000000..4bc5aca
+--- /dev/null
++++ include/views/general.script.execute-parallel.php
+@@ -0,0 +1,54 @@
++<?php
++/*
++** Zabbix
++** Copyright (C) 2000-2011 Zabbix SIA
++**
++** This program is free software; you can redistribute it and/or modify
++** it under the terms of the GNU General Public License as published by
++** the Free Software Foundation; either version 2 of the License, or
++** (at your option) any later version.
++**
++** This program is distributed in the hope that it will be useful,
++** but WITHOUT ANY WARRANTY; without even the implied warranty of
++** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++** GNU General Public License for more details.
++**
++** You should have received a copy of the GNU General Public License
++** along with this program; if not, write to the Free Software
++** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
USA.
++**/
++
++
++//javascript item
++$js = new CJSscript();
++
++$numHosts = count($this->data['hosts']);
++
++$js->addItem("<div id=\"counter\" 
style=\"font-size:20px;padding:5px;\">0/$numHosts</div>");
++$js->addItem("<div id=\"content\"></div>");
++$js->addItem("<script type=\"text/javascript\" 
src=\"js/jquery/jquery.js\"></script>");
++$js->addItem("<script type=\"text/javascript\">");
++$js->addItem("var hosts = new Array();");
++$js->addItem("var ctr = 0;");
++
++for($i = 0; $i < $numHosts; $i++)
++{
++    $host = $this->data['hosts'][$i];
++    $js->addItem("hosts[$i] = ".$host['hostid'].";");
++}
++
++$sid = $this->data['sid'];
++$scriptid = $this->data['scriptid'];
++$js->addItem("for(var i=0;i<$numHosts;i++){
++    $.ajax({
++    url: 
\"scripts_exec.php?sid=$sid&execute=1&scriptid=$scriptid&strip=1&hostid=\"+hosts[i],
++    async: true,
++    success: function(data) { $('#content').append(data); ctr++; 
$('#counter').html(ctr+'/$numHosts') }
++    });
++}");
++
++
++//$js->addItem();
++$js->addItem("</script>");
++
++return $js;
+diff --git include/views/general.script.execute.php 
include/views/general.script.execute.php
+index 5f8d2f6..19eaec8 100644
+--- include/views/general.script.execute.php
++++ include/views/general.script.execute.php
+@@ -27,8 +27,17 @@ $scriptForm->setName('scriptForm');
+ 
+ // append tabs to form
+ $scriptTab = new CTabView();
+-$scriptTab->addTab('scriptTab', _s('Result of "%s"', 
$this->data['info']['name']), new CSpan($this->data['message'], 'pre 
fixedfont'));
++$body = new CSpan($this->data['message'],'pre fixedfont');
++if(isset($this->data['error']))
++{
++    $body = new CList(null, "messages");
++    $body->addItem(new CListItem($this->data['error'], "error"));
++}
++
++//    $scriptTab->addTab('errorTab', _s('ERROR'), new 
CSpan($this->data['error'], 'pre fixedfont'));
++$scriptTab->addTab('scriptTab', _s('Result of "%s" ON 
'.$this->data['host']['name'], $this->data['info']['name']), $body);
+ $scriptForm->addItem($scriptTab);
+ 
+ $scriptWidget->addItem($scriptForm);
++$scriptWidget->addItem(BR());
+ return $scriptWidget;
+diff --git js/main.js js/main.js
+index 4f14d4d..2bceabb 100644
+--- js/main.js
++++ js/main.js
+@@ -103,7 +103,7 @@ var PageRefresh = {
+  * Main menu
+  */
+ var MMenu = {
+-      menus:                  {'empty': 0, 'view': 0, 'cm': 0, 'reports': 0, 
'config': 0, 'admin': 0},
++      menus:                  {'empty': 0, 'view': 0, 'cm': 0, 'reports': 0, 
'config': 0, 'admin': 0, 'experiment':0},
+       def_label:              null,
+       sub_active:     false,
+       timeout_reset:  null,
+diff --git manage_monitoring.php manage_monitoring.php
+new file mode 100644
+index 0000000..a01bbfa
+--- /dev/null
++++ manage_monitoring.php
+@@ -0,0 +1,61 @@
++<?php
++/*
++** Zabbix
++** Copyright (C) 2000-2011 Zabbix SIA
++**
++** This program is free software; you can redistribute it and/or modify
++** it under the terms of the GNU General Public License as published by
++** the Free Software Foundation; either version 2 of the License, or
++** (at your option) any later version.
++**
++** This program is distributed in the hope that it will be useful,
++** but WITHOUT ANY WARRANTY; without even the implied warranty of
++** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++** GNU General Public License for more details.
++**
++** You should have received a copy of the GNU General Public License
++** along with this program; if not, write to the Free Software
++** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
USA.
++**/
++
++require_once 'include/config.inc.php';
++require_once 'include/hosts.inc.php';
++require_once 'include/items.inc.php';
++require_once 'include/forms.inc.php';
++
++$page['title'] = _('Manage Monitoring');
++$page['file'] = 'manage_monitoring.php';
++
++define('ZBX_PAGE_NO_MENU', 1);
++
++// VAR        TYPE    OPTIONAL        FLAGS   VALIDATION      EXCEPTION
++$fields = array(
++      'template'      =>      array(T_ZBX_INT,        O_OPT,  P_SYS,          
DB_ID,  true),
++      'action'                =>      array(T_ZBX_STR,        O_OPT,  
NOT_EMPTY,      null,   true),
++);
++check_fields($fields);
++
++$templates = array_keys($_REQUEST['template']);
++
++//fetch template
++$options = array(
++      'templateids' => $templates,
++      'selectItems' => array(),
++      'output' => array('name')
++);
++$templates = API::Template()->get($options);
++
++//pull all item ids in array
++$all_items = array();
++foreach($templates as $temp)
++{
++      foreach($temp['items'] as $item)
++              $all_items[] = $item['itemid'];
++}
++
++//perform action
++DBstart();
++$go_result = ($_REQUEST['action'] == 
'disable')?disable_item($all_items):activate_item($all_items);
++$go_result = DBend($go_result);
++
++jsRedirect('dashboard.php');
+diff --git results.php results.php
+new file mode 100644
+index 0000000..6cf8a87
+--- /dev/null
++++ results.php
+@@ -0,0 +1,101 @@
++<?php
++
++require_once dirname(__FILE__).'/include/config.inc.php';
++require_once dirname(__FILE__).'/include/experiments/inc.php';
++
++$page['title'] = _('Experiment Results');
++$page['file'] = 'results.php';
++$page['hist_arg'] = array('resid');
++
++require_once dirname(__FILE__).'/include/page_header.php';
++
++// VAR        TYPE    OPTIONAL        FLAGS   VALIDATION      EXCEPTION
++$fields = array(
++    'runid' =>   array(T_ZBX_INT, O_OPT, P_SYS|P_ACT, null, null),
++    'hostid' =>   array(T_ZBX_INT, O_OPT, P_SYS|P_ACT, null, null),
++    'delete' =>    array(T_ZBX_INT, O_OPT, P_SYS|P_ACT, null, null),
++    'interrupt' =>    array(T_ZBX_INT, O_OPT, P_SYS|P_ACT, null, null),
++    'rerun' =>    array(T_ZBX_INT, O_OPT, P_SYS|P_ACT, null, null)
++);
++check_fields($fields);
++
++/*
++ * Actions
++ */
++
++if(isset($_REQUEST['delete']))
++{
++    if(exprun_checkpermission($_REQUEST['delete']))
++    {
++        exprun_delete($_REQUEST['delete']);    
++        jsRedirect('results.php');
++    }
++    else
++        error("No permission to delete.");
++}
++
++if(isset($_REQUEST['interrupt']))
++{
++    if(exprun_checkpermission($_REQUEST['interrupt']))
++    {
++        exprun_interrupt($_REQUEST['interrupt']);
++        jsRedirect('results.php');
++    }
++    else
++        error("No permission to interrupt.");
++}
++
++if(isset($_REQUEST['rerun']))
++{
++    if(exprun_checkpermission($_REQUEST['rerun']))
++    {
++        exprun_rerun($_REQUEST['rerun']);
++        jsRedirect('results.php');
++    }
++    else
++        error("No permission to rerun.");
++}
++
++/*
++ * Display
++ */
++$resView = new CView('experiments.results');
++
++$results = exprun_getall(true);
++$resView->set('results', $results);
++
++if(isset($_REQUEST['runid']))
++{
++    if(exprun_verifyid($_REQUEST['runid']))
++    {
++        foreach($results as $r) //get the specific run that we want to 
display the log for
++        {
++            if($r['runid'] == $_REQUEST['runid'])
++            {
++                $run = $r;
++                break;
++            }
++        }
++        
++        $sep = 
"\n=================================================================\n";
++        $log = '';
++        foreach($run['nodes'] as $n)
++        {
++            if(isset($_REQUEST['hostid']) && $n['hostid'] == 
$_REQUEST['hostid']) //print the log of only a specific host
++            {
++                $log = $n['log'];
++                break;
++            }
++            else
++                $log .= $n['log'].$sep;
++        }
++        
++        $resView->set('log', $log);
++        $resView->set('runid', $run['runid']);
++    }
++}
++
++$resView->render();
++$resView->show();
++
++require_once dirname(__FILE__).'/include/page_footer.php';
+diff --git scripts_exec.php scripts_exec.php
+index d40b5a0..94775ee 100644
+--- scripts_exec.php
++++ scripts_exec.php
+@@ -27,23 +27,28 @@ $page['file'] = 'scripts_exec.php';
+ 
+ define('ZBX_PAGE_NO_MENU', 1);
+ 
+-require_once ('include/page_header.php');
++$strip = isset($_REQUEST['strip']);
++if(!$strip)
++    require_once ('include/page_header.php');
+ 
+ // VAR        TYPE    OPTIONAL        FLAGS   VALIDATION      EXCEPTION
+ $fields = array(
+-      'hostid' =>             array(T_ZBX_INT, O_OPT, P_SYS, DB_ID,           
'isset({execute})'),
++      'hostid' =>             array(T_ZBX_INT, O_OPT, P_SYS, DB_ID,           
'!isset({groupid})&&!isset({hosts})'),
+       'scriptid' =>   array(T_ZBX_INT, O_OPT, P_SYS, DB_ID,           
'isset({execute})'),
++      'groupid' =>    array(T_ZBX_INT, O_OPT, P_SYS, DB_ID,       
'!isset({hostid})&&!isset({hosts})'),
++      'hosts' =>              array(T_ZBX_INT, O_OPT, P_SYS, DB_ID,       
'!isset({hostid})&&!isset({groupid})'),
+       'execute' =>    array(T_ZBX_INT, O_OPT, P_ACT, IN('0,1'),       null)
+ );
+ check_fields($fields);
+ 
+-if (isset($_REQUEST['execute'])) {
+-      $scriptid = get_request('scriptid');
+-      $hostid = get_request('hostid');
+-
+-      $data = array(
++function execute_script($scriptid, $hostid)
++{
++    global $strip;
++    
++    $data = array(
+               'message' => '',
+-              'info' => DBfetch(DBselect('SELECT s.name FROM scripts s WHERE 
s.scriptid='.$scriptid))
++              'info' => DBfetch(DBselect('SELECT s.name FROM scripts s WHERE 
s.scriptid='.$scriptid)),
++              'host' => DBfetch(DBselect('SELECT h.name FROM hosts h WHERE 
h.hostid='.$hostid))
+       );
+ 
+       $result = API::Script()->execute(array('hostid' => $hostid, 'scriptid' 
=> $scriptid));
+@@ -53,8 +58,10 @@ if (isset($_REQUEST['execute'])) {
+               $isErrorExist = true;
+       }
+       elseif ($result['response'] == 'failed') {
+-              error($result['value']);
+-              $isErrorExist = true;
++          if($strip) $data['error'] = $result['value'];
++              else
++                  error($result['value']);
++          $isErrorExist = true;
+       }
+       else {
+               $data['message'] = $result['value'];
+@@ -70,4 +77,46 @@ if (isset($_REQUEST['execute'])) {
+       $scriptView->show();
+ }
+ 
+-require_once 'include/page_footer.php';
++if (isset($_REQUEST['execute'])) {
++      $scriptid = get_request('scriptid');
++      
++      if(isset($_REQUEST['groupid']) || isset($_REQUEST['hosts']))
++      {
++              if(isset($_REQUEST['groupid']))
++              {
++                      $groupid = get_request('groupid');
++                      
++                      $hosts = API::Host()->get(array(
++                              'groupids' => array($groupid),
++                              'editable' => 1,
++                              'output' => API_OUTPUT_EXTEND
++                      ));
++              }
++              else
++              {
++                      $hosts = API::Host()->get(array(
++                              'hostids' => get_request('hosts'),
++                              'editable' => 1,
++                              'output' => API_OUTPUT_EXTEND
++                      ));
++              }
++              
++              $data = array();
++              $data['hosts'] = $hosts;
++              $data['scriptid'] = $scriptid;
++              $data['sid'] = get_request('sid');
++              
++              $scriptView = new CView('general.script.execute-parallel', 
$data);
++      $scriptView->render();
++      $scriptView->show();
++              
++      }
++      elseif(isset($_REQUEST['hostid']))
++      {
++          $hostid = get_request('hostid');
++      execute_script($scriptid, $hostid);
++      }
++}
++
++if(!$strip)
++    require_once 'include/page_footer.php';
+diff --git targets.php targets.php
+new file mode 100644
+index 0000000..0d5e121
+--- /dev/null
++++ targets.php
+@@ -0,0 +1,50 @@
++<?php
++
++error_reporting(E_ALL & ~E_DEPRECATED & ~E_STRICT);
++
++require_once dirname(__FILE__).'/include/config.inc.php';
++require_once dirname(__FILE__).'/include/experiments/inc.php';
++
++$page['title'] = _('Target Configuration');
++$page['file'] = 'targets.php';
++$page['hist_arg'] = array('targetid');
++
++require_once dirname(__FILE__).'/include/page_header.php';
++
++/*
++ * Actions
++ */
++//print_r($_REQUEST);
++
++if(isset($_REQUEST['target']) && isset($_REQUEST['apply']))
++{
++    switch($_REQUEST['target'])
++    {
++        case 'ssh':
++            if(isset($_REQUEST['sshhosts']))
++                expssh_updatehosts($_REQUEST['sshhosts']);
++        
++            break;
++        
++        case 'planetlab':
++            if(isset($_REQUEST['plnodes']) && is_array($_REQUEST['plnodes']))
++                exppl_updateSliceNodes($_REQUEST['plnodes']);
++            break;
++    }
++}
++
++/*
++ * Display
++ */
++$targetsView = new CView('experiments.targets');
++
++$targetsView->set('targetlist', $exp_targetlist);
++if(isset($_REQUEST['target'])) $targetsView->set('selected_target', 
$_REQUEST['target']);
++$targetsView->set('sshhosts', expnodes_gethosts('ssh'));
++if(isset($_REQUEST['ploffset'])) $targetsView->set('ploffset', 
$_REQUEST['ploffset']);
++if(isset($_REQUEST['plfilter']) && trim($_REQUEST['plfilter']) != '') 
$targetsView->set('plfilter', $_REQUEST['plfilter']);
++
++$targetsView->render();
++$targetsView->show();
++
++require_once dirname(__FILE__).'/include/page_footer.php';
+diff --git tasklist.php tasklist.php
+new file mode 100644
+index 0000000..fa43c0d
+--- /dev/null
++++ tasklist.php
+@@ -0,0 +1,104 @@
++<?php
++
++require_once dirname(__FILE__).'/include/config.inc.php';
++require_once dirname(__FILE__).'/include/experiments/inc.php';
++
++$page['title'] = _('Tasklists');
++$page['file'] = 'tasklist.php';
++$page['hist_arg'] = array('taskid');
++
++require_once dirname(__FILE__).'/include/page_header.php';
++
++// VAR        TYPE    OPTIONAL        FLAGS   VALIDATION      EXCEPTION
++/*$fields = array(
++      'tid' =>                array(T_ZBX_INT, O_OPT, P_SYS, null, null),
++);
++check_fields($fields);*/
++
++
++/*
++ * Actions
++ */
++if(isset($_REQUEST['tid']) && isset($_REQUEST['update']))
++{
++    $tid = intval($_REQUEST['tid']);
++    if(exptasklist_allowed($tid) == 2) //check user permission (read/write)
++        exptasklist_update($tid, $_REQUEST);
++    else
++        error("Permission denied!");
++}
++if(isset($_REQUEST['add']))
++{
++    if(exptasklist_add($_REQUEST))
++        jsRedirect('tasklist.php');
++}
++if(isset($_REQUEST['delete']))
++{
++    $tid = intval(substr($_REQUEST['delete'], 1));
++    
++    if(exptasklist_allowed($tid) == 2)
++    {
++        if(exptasklist_delete($tid))
++            jsRedirect('tasklist.php');
++    }
++    else
++        error("Permission denied!");
++}
++
++
++/*
++ * Display
++ */
++if(isset($_REQUEST['tid']))
++{
++    $tid = intval($_REQUEST['tid']);
++    if(exptasklist_allowed($tid) > 0) //check user permission (read or 
read/write)
++    {
++        //Get tasklist metadata
++        $meta = exptasklist_getbyid($tid);
++        //Get tasklist XML content
++        $xml = exptasklist_getcontent($tid);
++        if($xml)
++        {
++            $tlView = new CView('experiments.tasklist.edit');
++
++            $tlView->set('tid', $tid);
++            $tlView->set('xml', simplexml_load_string($xml));
++            //$tlView->set('targets', exp_gettargets());
++            $tlView->set('meta', $meta);
++            $tlView->set('exptasklist_defaults', $exptasklist_defaults);
++            $tlView->set('userfiles', expfiles_getuserfiles());
++
++            $tlView->render();
++            $tlView->show();
++
++        }
++        else
++            error("Error while loading tasklist!");
++    }
++    else
++        error("Permission denied!");
++}
++elseif(isset($_REQUEST['new']))
++{
++    $tlView = new CView('experiments.tasklist.edit');
++    
++    $tlView->set('new', true);
++    //$tlView->set('targets', exp_gettargets());
++    $tlView->set('exptasklist_defaults', $exptasklist_defaults);
++    $tlView->set('userfiles', expfiles_getuserfiles());
++    
++    $tlView->render();
++    $tlView->show();
++}
++else
++{
++    $tlView = new CView('experiments.tasklist');
++    
++    $tlView->set('tasklists', exptasklist_getall(true));
++    
++    $tlView->render();
++    $tlView->show();
++}
++
++require_once dirname(__FILE__).'/include/page_footer.php';

Added: eclectic/gplmt-ui/Zabbix-2.0/schema.sql
===================================================================
--- eclectic/gplmt-ui/Zabbix-2.0/schema.sql                             (rev 0)
+++ eclectic/gplmt-ui/Zabbix-2.0/schema.sql     2014-05-26 19:45:47 UTC (rev 
33405)
@@ -0,0 +1,139 @@
+-- phpMyAdmin SQL Dump
+-- version 3.4.11.1deb2
+-- http://www.phpmyadmin.net
+--
+-- Host: localhost
+-- Generation Time: Sep 26, 2013 at 04:39 PM
+-- Server version: 5.5.31
+-- PHP Version: 5.4.4-14+deb7u4
+
+SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
+SET time_zone = "+00:00";
+
+
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
+/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
+/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
+/*!40101 SET NAMES utf8 */;
+
+--
+-- Database: `zabbix`
+--
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `exp_config`
+--
+
+CREATE TABLE IF NOT EXISTS `exp_config` (
+  `configid` int(11) NOT NULL AUTO_INCREMENT,
+  `section` varchar(100) COLLATE utf8_bin NOT NULL,
+  `name` varchar(200) COLLATE utf8_bin NOT NULL,
+  `label` varchar(100) COLLATE utf8_bin NOT NULL,
+  `description` text COLLATE utf8_bin,
+  `type` varchar(100) COLLATE utf8_bin NOT NULL,
+  `default_value` varchar(500) COLLATE utf8_bin NOT NULL,
+  `user_editable` tinyint(1) NOT NULL,
+  PRIMARY KEY (`configid`)
+) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=29 ;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `exp_configenum`
+--
+
+CREATE TABLE IF NOT EXISTS `exp_configenum` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `configid` int(11) NOT NULL,
+  `label` text COLLATE utf8_bin NOT NULL,
+  `value` text COLLATE utf8_bin NOT NULL,
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=3 ;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `exp_host`
+--
+
+CREATE TABLE IF NOT EXISTS `exp_host` (
+  `hostid` int(11) NOT NULL AUTO_INCREMENT,
+  `target` varchar(200) COLLATE utf8_bin NOT NULL,
+  `userid` int(11) NOT NULL,
+  `host` text COLLATE utf8_bin NOT NULL,
+  `pl_nodeid` int(11) DEFAULT NULL,
+  PRIMARY KEY (`hostid`,`target`)
+) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=1580 ;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `exp_run`
+--
+
+CREATE TABLE IF NOT EXISTS `exp_run` (
+  `runid` int(11) NOT NULL AUTO_INCREMENT,
+  `startedon` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  `usetasklist` tinyint(1) NOT NULL DEFAULT '1',
+  `tasklistid` int(11) DEFAULT NULL,
+  `command` varchar(200) COLLATE utf8_bin DEFAULT NULL,
+  `target` varchar(200) COLLATE utf8_bin NOT NULL,
+  `pid` int(11) DEFAULT NULL,
+  `userid` int(11) NOT NULL,
+  `status` int(11) NOT NULL DEFAULT '0',
+  `percentage` double NOT NULL DEFAULT '0',
+  `fullcommand` text COLLATE utf8_bin,
+  PRIMARY KEY (`runid`)
+) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=75 ;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `exp_runnode`
+--
+
+CREATE TABLE IF NOT EXISTS `exp_runnode` (
+  `runid` int(11) NOT NULL,
+  `hostid` int(11) NOT NULL,
+  `target` varchar(200) COLLATE utf8_bin NOT NULL,
+  `status` int(11) NOT NULL DEFAULT '0',
+  `percentage` double NOT NULL DEFAULT '0',
+  `log` text COLLATE utf8_bin NOT NULL,
+  PRIMARY KEY (`runid`,`hostid`,`target`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `exp_tasklist`
+--
+
+CREATE TABLE IF NOT EXISTS `exp_tasklist` (
+  `tasklistid` int(11) NOT NULL AUTO_INCREMENT,
+  `name` varchar(100) COLLATE utf8_bin NOT NULL,
+  `description` text COLLATE utf8_bin,
+  `fsname` varchar(100) COLLATE utf8_bin NOT NULL,
+  `userid` int(11) NOT NULL,
+  `shared` tinyint(1) NOT NULL,
+  PRIMARY KEY (`tasklistid`)
+) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=24 ;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `exp_userconfig`
+--
+
+CREATE TABLE IF NOT EXISTS `exp_userconfig` (
+  `configid` int(11) NOT NULL,
+  `userid` int(11) NOT NULL,
+  `value` varchar(500) COLLATE utf8_bin NOT NULL,
+  `enabled` tinyint(1) NOT NULL,
+  PRIMARY KEY (`configid`,`userid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+
+/*!40101 SET address@hidden */;
+/*!40101 SET address@hidden */;
+/*!40101 SET address@hidden */;

Added: eclectic/gplmt-ui/Zabbix-2.2/README
===================================================================
--- eclectic/gplmt-ui/Zabbix-2.2/README                         (rev 0)
+++ eclectic/gplmt-ui/Zabbix-2.2/README 2014-05-26 19:45:47 UTC (rev 33405)
@@ -0,0 +1,8 @@
+GPLMT Web UI
+============
+
+This is a diff which has to be applied against Zabbix version 2.2
+
+schema.sql and data.sql to be applied to Zabbix mysql database
+
+See ../installation-guide.pdf for more details

Added: eclectic/gplmt-ui/Zabbix-2.2/data.sql
===================================================================
--- eclectic/gplmt-ui/Zabbix-2.2/data.sql                               (rev 0)
+++ eclectic/gplmt-ui/Zabbix-2.2/data.sql       2014-05-26 19:45:47 UTC (rev 
33405)
@@ -0,0 +1,37 @@
+-- phpMyAdmin SQL Dump
+-- version 3.4.11.1deb2
+-- http://www.phpmyadmin.net
+--
+-- Host: localhost
+-- Generation Time: Sep 26, 2013 at 04:40 PM
+-- Server version: 5.5.31
+-- PHP Version: 5.4.4-14+deb7u4
+
+SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
+SET time_zone = "+00:00";
+
+
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
+/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
+/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
+/*!40101 SET NAMES utf8 */;
+
+--
+-- Database: `zabbix`
+--
+
+--
+-- Dumping data for table `exp_config`
+--
+
+INSERT INTO `exp_config` VALUES (1,'ssh','ssh_username','SSH 
username','Username for SSH access','text','',1),(2,'ssh','ssh_password','SSH 
password','Password for SSH access or password for the SSH 
keyfile','password','',1),(3,'ssh','ssh_keyfile','SSH keyfile','SSH key for 
login','file','',1),(16,'gplmt','notification','Notification','Which 
notification mechanism to use: simple, 
result','text','result',0),(17,'gplmt','max_parallelism','Max 
Parallelism','Number of parallel workers, use 0 for 
unlimited','integer','10',0),(18,'planetlab','slice','Planetlab Slice','Name of 
your PlanetLab Slice','text','',1),(20,'planetlab','api_url','PLC/PLE','Use 
PlanetLab Central or PlanetLab 
Europe','enum','https://www.planet-lab.eu/PLCAPI/',1),(21,'planetlab','username','PlanetLab
 API username','Your login to the planetlab website\r\nto access the planetlab 
API','text','',1),(22,'planetlab','password','PlanetLab API password','Your 
password for the planetlab\r\nwebsite to access the planetla
 b API','
 password','',1),(25,'ssh','ssh_transfer','SSH Transfer','Protocol for put get 
operations: scp, sftp','text','scp',0),(26,'ssh','ssh_use_known_hosts','SSH: 
Use Known Hosts','Use system\'s SSH \"known hosts\" 
file','boolean','yes',0),(27,'ssh','add_unkown_hostkeys','SSH: Add Unknown 
Hostkeys','Add node hostkeys 
automatically','boolean','yes',0),(28,'gplmt','userdir','User Directory','User 
specific directory for put/get 
operations','text','',0),(31,'planetlab','pl_keyfile','Planetlab 
keyfile','Private key file for connecting to planetlab 
nodes','file','',1),(32,'planetlab','pl_keyfile_password','Planetlab keyfile 
password','Password used to unlock private key file (if 
needed)','password','',1),(33,'hen','hen_gw','Gateway server','Which HEN 
gateway server to connect 
to','enum','cockerel.cs.ucl.ac.uk',1),(34,'hen','hen_gw_username','Gateway 
username','Username used to connect to HEN 
gateway','text','',1),(35,'hen','hen_gw_keyfile','Gateway keyfile','Private key 
file used to authe
 nticate 
 HEN gateway','file','',1),(36,'hen','hen_gw_keyfile_password','Gateway keyfile 
password','Password used to unlock private key file for HEN gateway 
authentication. Leave blank if not 
needed.','password','',1),(37,'hen','hen_node_username','Node 
username','Username used to connect to HEN 
node','text','',1),(38,'hen','hen_node_keyfile','Node keyfile','Private key 
file used to authenticate against HEN node. Leave empty if using password 
authentication.','file','',1),(39,'hen','hen_node_password','Node 
password','Password used for authentication against HEN node OR unlocking 
private key file.','password','',1);
+
+--
+-- Dumping data for table `exp_configenum`
+--
+
+INSERT INTO `exp_configenum` VALUES (1,20,'Planetlab 
Central','https://www.planet-lab.org/PLCAPI/'),(2,20,'Planetlab 
Europe','https://www.planet-lab.eu/PLCAPI/'),(3,33,'cockerel.cs.ucl.ac.uk','cockerel.cs.ucl.ac.uk'),(4,33,'hen.cs.ucl.ac.uk','hen.cs.ucl.ac.uk');
+
+/*!40101 SET address@hidden */;
+/*!40101 SET address@hidden */;
+/*!40101 SET address@hidden */;

Added: eclectic/gplmt-ui/Zabbix-2.2/patch.diff
===================================================================
--- eclectic/gplmt-ui/Zabbix-2.2/patch.diff                             (rev 0)
+++ eclectic/gplmt-ui/Zabbix-2.2/patch.diff     2014-05-26 19:45:47 UTC (rev 
33405)
@@ -0,0 +1,3157 @@
+diff --git conf.php conf.php
+new file mode 100644
+index 0000000..c88d8a6
+--- /dev/null
++++ conf.php
+@@ -0,0 +1,31 @@
++<?php
++
++require_once dirname(__FILE__).'/include/config.inc.php';
++require_once dirname(__FILE__).'/include/experiments/inc.php';
++
++$page['title'] = _('User Configuration');
++$page['file'] = 'conf.php';
++$page['hist_arg'] = array('confid');
++
++require_once dirname(__FILE__).'/include/page_header.php';
++
++/*
++ * Actions
++ */
++if(isset($_REQUEST['update']))
++{
++    //print_r($_REQUEST);
++    expconfig_update($_REQUEST);
++}
++
++/*
++ * Display
++ */
++$filesView = new CView('experiments.conf');
++
++$filesView->set('conf', expconfig_getuserconfig());
++
++$filesView->render();
++$filesView->show();
++
++require_once dirname(__FILE__).'/include/page_footer.php';
+diff --git conf/.gitignore conf/.gitignore
+new file mode 100644
+index 0000000..d6cdf1c
+--- /dev/null
++++ conf/.gitignore
+@@ -0,0 +1 @@
++zabbix.conf.php
+diff --git execute.php execute.php
+new file mode 100644
+index 0000000..1afdbb4
+--- /dev/null
++++ execute.php
+@@ -0,0 +1,95 @@
++<?php
++
++require_once dirname(__FILE__).'/include/config.inc.php';
++require_once dirname(__FILE__).'/include/experiments/inc.php';
++
++$page['title'] = _('Deploy & Execute');
++$page['file'] = 'execute.php';
++$page['hist_arg'] = array('execid');
++$page['scripts'] = array('multiselect.js');
++
++require_once dirname(__FILE__).'/include/page_header.php';
++
++// VAR        TYPE    OPTIONAL        FLAGS   VALIDATION      EXCEPTION
++/*$fields = array(
++      'run' =>                array(T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, 
null),
++      'nodes' =>              array(T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, 
'isset({run})'),
++      'usetasklist' =>   array(T_ZBX_INT, O_OPT, P_SYS|P_ACT, IN('0,1'), 
'isset({run})'),
++      'tasklist' =>   array(T_ZBX_INT, O_OPT, P_SYS|P_ACT, null, 
'isset({run})'),
++      'cmd' =>   array(T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, 'isset({run})'),
++      'sync' =>   array(T_ZBX_INT, O_OPT, null, null, null)
++);
++check_fields($fields);*/
++
++
++/*
++ * Actions
++ */
++
++if(isset($_REQUEST['unlink']) && is_array($_REQUEST['unlink']) && 
isset($_REQUEST['templates']) && is_array($_REQUEST['templates']))
++{
++    foreach($_REQUEST['unlink'] as $tid => $tname)
++        unset($_REQUEST['templates'][$tid]);
++    unset($_REQUEST['unlink']);
++}
++
++if(isset($_REQUEST['run']))
++{
++    $usetasklist = intval($_REQUEST['usetasklist']);
++    $tasklist = intval($_REQUEST['tasklist']);
++
++    $cmd = trim($_REQUEST['cmd']);
++    $cmd_empty = empty($cmd);
++    
++    $monitor = isset($_REQUEST['monitor']);
++    
++    if($usetasklist == 0 && $cmd_empty)
++        error("Please specify the command to run.");
++    elseif(!isset($_REQUEST['target']))
++        error("Please specify target.");
++    elseif(!isset($_REQUEST[$_REQUEST['target'].'hosts']) || 
count($_REQUEST[$_REQUEST['target'].'hosts']) == 0)
++        error('Please select targets.');
++    elseif($monitor && (!isset($_REQUEST['expname']) || $_REQUEST['expname'] 
== ''))
++        error('Please specify experiment name');
++    elseif($monitor && (!isset($_REQUEST['templates']) || 
count($_REQUEST['templates']) == 0))
++        error('Please specify monitor templates');
++    elseif( $monitor && !preg_match('/^([0-9a-zA-Z_\. \-]+)$/', 
$_REQUEST['expname']) )
++        error('Invalid characters in experiment name');
++    else
++    {
++        $hosts = $_REQUEST[$_REQUEST['target'].'hosts'];
++
++        if($monitor)
++        {
++            $expname = $_REQUEST['expname'];
++            $templates = $_REQUEST['templates'];
++        }
++        else
++        {
++            $expname = '';
++            $templates = array();
++        }
++
++        $res = exprun_new($_REQUEST['target'], $hosts, $usetasklist, 
$tasklist, $cmd, $monitor, $expname, $templates);
++        if($res == EXP_OK)
++            jsRedirect('results.php');
++        else
++            error(exp_errorstring($res));
++    }
++}
++
++/*
++ * Display
++ */
++
++$execView = new CView('experiments.execute');
++
++$execView->set('tasklists', exptasklist_getall());
++$execView->set('targets', $exp_targetlist);
++//$execView->set('currenttarget', 
isset($_REQUEST['target'])?$_REQUEST['target']:reset($exp_targetlist));
++$execView->set('data', $_REQUEST);
++
++$execView->render();
++$execView->show();
++
++require_once dirname(__FILE__).'/include/page_footer.php';
+diff --git files.php files.php
+new file mode 100644
+index 0000000..5326ccc
+--- /dev/null
++++ files.php
+@@ -0,0 +1,58 @@
++<?php
++
++require_once dirname(__FILE__).'/include/config.inc.php';
++require_once dirname(__FILE__).'/include/experiments/inc.php';
++
++$page['title'] = _('User Files');
++$page['file'] = 'files.php';
++$page['hist_arg'] = array('fileid');
++
++//before any headers are written, check if trying to download
++if(isset($_REQUEST['download']))
++{
++    $filename = $_REQUEST['download'];
++    
++    expfiles_download($filename);
++}
++
++require_once dirname(__FILE__).'/include/page_header.php';
++
++// VAR        TYPE    OPTIONAL        FLAGS   VALIDATION      EXCEPTION
++/*$fields = array(
++);
++check_fields($fields);*/
++
++/*
++ * Actions
++ */
++if(isset($_REQUEST['upload']) && isset($_FILES['file']))
++{
++    //some validations
++    if($_FILES["file"]["error"] > 0)
++        error('File upload error: '.$_FILES["file"]["error"]);
++    else
++    {
++        $filename = $_FILES["file"]["name"];
++        $fullpath = expfiles_getnewfilepath($filename);
++        move_uploaded_file($_FILES["file"]["tmp_name"], $fullpath);
++        
++        info("File uploaded successfully.");
++    }
++}
++if(isset($_REQUEST['delete']))
++{
++    if(expfiles_delete($_REQUEST['delete'])) jsRedirect('files.php');
++}
++
++/*
++ * Display
++ */
++$filesView = new CView('experiments.files');
++
++$filesView->set('files', expfiles_getuserfiles());
++
++$filesView->render();
++$filesView->show();
++
++
++require_once dirname(__FILE__).'/include/page_footer.php';
+diff --git include/classes/import/CXmlImport18.php 
include/classes/import/CXmlImport18.php
+index 52897cb..f8a5bde 100644
+--- include/classes/import/CXmlImport18.php
++++ include/classes/import/CXmlImport18.php
+@@ -1004,7 +1004,7 @@ class CXmlImport18 {
+                               $host_db['groups'] = array();
+                               $groups_to_parse = array();
+                               foreach ($groups as $group) {
+-                                      $groups_to_parse[] = array('name' => 
$group->nodeValue);
++                                      $groups_to_parse[] = array('name' => 
trim($group->nodeValue));
+                               }
+                               if (empty($groups_to_parse)) {
+                                       $groups_to_parse[] = array('name' => 
ZBX_DEFAULT_IMPORT_HOST_GROUP);
+@@ -1133,6 +1133,7 @@ class CXmlImport18 {
+ 
+                                       $templateLinkage = array();
+                                       foreach ($templates as $template) {
++                                              $template->nodeValue = 
trim($template->nodeValue);
+                                               $options = array(
+                                                       'filter' => 
array('host' => $template->nodeValue),
+                                                       'output' => 
array('templateid'),
+diff --git include/experiments/conf.php include/experiments/conf.php
+new file mode 100644
+index 0000000..7688d4b
+--- /dev/null
++++ include/experiments/conf.php
+@@ -0,0 +1,9 @@
++<?php
++
++$GLOBALS['GPLMT_DIR'] = '/home/omar/workspace/eclectic/gplmt/';
++
++$GLOBALS['GPLMT_TASKLISTS_DIR'] = $GLOBALS['GPLMT_DIR'].'contrib/tasklists/';
++$GLOBALS['GPLMT_CONF_DIR'] = $GLOBALS['GPLMT_DIR'].'contrib/configurations/';
++$GLOBALS['GPLMT_NODES_DIR'] = $GLOBALS['GPLMT_DIR'].'contrib/nodes/';
++$GLOBALS['GPLMT_RESULTS_DIR'] = $GLOBALS['GPLMT_DIR'].'contrib/results/';
++$GLOBALS['GPLMT_FILES_DIR'] = $GLOBALS['GPLMT_DIR'].'contrib/files/';
+diff --git include/experiments/config.php include/experiments/config.php
+new file mode 100644
+index 0000000..1e4ed5a
+--- /dev/null
++++ include/experiments/config.php
+@@ -0,0 +1,106 @@
++<?php
++
++function expconfig_update($data)
++{
++    //get user editable config
++    $editable = expconfig_getuserconfig();
++    
++    foreach($data as $k => $v)
++    {
++        if(!isset($editable[$k])) continue;
++        $v = trim($v);
++        $enabled = ($v != '');
++        
++        if(($editable[$k]['type'] == 'file') && $enabled)
++            $v = expfiles_getuserdir().exp_cleanfilename($v);
++        
++        expdb_update('exp_userconfig',
++            array('value' => $v, 'enabled' => strval($enabled)),
++            array('configid' => $k, 'userid' => CWebUser::$data['userid']));
++    }
++    
++    expconfig_writefile();
++}
++
++function expconfig_getconfigbyname($configname)
++{
++    $uid = CWebUser::$data['userid'];
++    $sql = "SELECT exp_userconfig.value, exp_userconfig.enabled
++        FROM exp_config, exp_userconfig
++        WHERE exp_config.configid = exp_userconfig.configid
++        AND exp_config.name = '$configname'
++        AND exp_userconfig.userid = $uid";
++    $result = DBfetchArray(DBselect($sql));
++    if(count($result) == 0) return null;
++    if(!$result[0]['enabled']) return null;
++    return $result[0]['value'];
++}
++
++function expconfig_getuserconfig($editableOnly = true)
++{
++    $uid = CWebUser::$data['userid'];
++    $sql = "SELECT u.configid, c.section, c.name, c.label, c.description, 
c.type, u.value
++            FROM exp_config c, exp_userconfig u
++            WHERE c.configid = u.configid
++            AND c.user_editable = 1
++            AND u.userid = $uid
++            ORDER BY c.section, c.configid";
++    return DBfetchArrayAssoc(DBselect($sql), 'configid');
++}
++
++function expconfig_getenum($configid)
++{
++    return expdb_select('exp_configenum', array('configid' => $configid));
++}
++
++function expconfig_writefile()
++{
++    $uid = CWebUser::$data['userid'];
++    $sql = "SELECT c.section, c.name, u.value
++            FROM exp_config c, exp_userconfig u
++            WHERE c.configid = u.configid
++            AND u.enabled = 1
++            AND u.userid = $uid
++            ORDER BY c.section";
++    $conf = DBfetchArray(DBselect($sql));
++    
++    $filename = $GLOBALS['GPLMT_CONF_DIR'].strval($uid);
++    $f = fopen($filename, 'w+');
++    $current_sec = '';
++    
++    foreach($conf as $c)
++    {
++        if($c['section'] != $current_sec)
++        {
++            $current_sec = $c['section'];
++            fwrite($f, "[$current_sec]\n");
++        }
++        $k = $c['name'];
++        $v = $c['value'];
++        fwrite($f, "$k = $v\n");
++    }
++    fclose($f);
++}
++
++function expconfig_verifyuserconfig()
++{
++    $uid = CWebUser::$data['userid'];
++    $default_config = expdb_select('exp_config', array(), 'configid');
++    $user_config = expdb_select('exp_userconfig', array('userid' => $uid), 
'configid');
++    
++    if(count($default_config) == count($user_config)) return;
++    
++    foreach($default_config as $dc_k => $dc)
++    {
++        if(isset($user_config[$dc_k])) continue;
++        
++        $newval = $dc['default_value'];
++        if($dc['name'] == 'userdir') //special cases, user specific
++            $newval = expfiles_getuserdir();
++        $enabled = strval(($newval != ''));
++        
++        expdb_insert('exp_userconfig',
++            array('configid' => $dc_k, 'userid' => $uid, 'value' => $newval, 
'enabled' => $enabled));
++    }
++    expconfig_writefile();
++}
+diff --git include/experiments/db.php include/experiments/db.php
+new file mode 100644
+index 0000000..3c89fe5
+--- /dev/null
++++ include/experiments/db.php
+@@ -0,0 +1,95 @@
++<?php
++
++function expdb_genwhere($where)
++{
++    if(sizeof($where) == 0) return '';
++    
++    $where_str = ' WHERE ';
++    
++    $first = true;
++    foreach($where as $k => $v)
++    {
++        if(!$first) $where_str .= ' AND ';
++        else $first = false;
++        $where_str .= $k.'=';
++        if(is_string($v))
++            $where_str .= zbx_dbstr(trim($v));
++        else
++            $where_str .= $v;
++    }
++    
++    return $where_str;
++}
++
++function expdb_getlastid($table)
++{
++  $sql = "SELECT LAST_INSERT_ID() AS id;";
++  
++  $res = DBfetchArray(DBselect($sql));
++  if(count($res) == 0)
++    return 0;
++  return $res[0]['id'];
++}
++
++function expdb_insert($table, $data)
++{
++    $keys_str = implode(',', array_keys($data));
++    
++    $vals = array();
++    foreach($data as $v)
++    {
++        if(is_string($v)) $vals[] = zbx_dbstr(trim($v));
++        else $vals[] = $v;
++    }
++    
++    $vals_str = implode(',', $vals);
++    
++    $sql = "INSERT INTO $table ($keys_str) VALUES ($vals_str)";
++    
++    DBexecute($sql);
++    return expdb_getlastid($table);
++}
++
++function expdb_update($table, $data, $where)
++{
++    $set_str = '';
++    $first = true;
++    foreach($data as $k => $v)
++    {
++        if(!$first) $set_str .= ',';
++        else $first = false;
++        $set_str .= $k.'=';
++        if(is_string($v))
++            $set_str .= zbx_dbstr(trim($v));
++        else
++            $set_str .= $v;
++    }
++    
++    $where_str = expdb_genwhere($where);
++    
++    $sql = "UPDATE $table SET $set_str $where_str";
++    
++    return DBexecute($sql);
++}
++
++
++function expdb_select($table, $where, $assocField = null)
++{
++    $where_str = expdb_genwhere($where);
++    
++    $sql = "SELECT * FROM $table $where_str";
++    
++    if($assocField)
++        return DBfetchArrayAssoc(DBselect($sql), $assocField);
++    else
++        return DBfetchArray(DBselect($sql));
++}
++
++function expdb_delete($table, $where)
++{
++    $where_str = expdb_genwhere($where);
++    
++    $sql = "DELETE FROM $table $where_str";
++    
++    return DBexecute($sql);
++}
+diff --git include/experiments/files.php include/experiments/files.php
+new file mode 100644
+index 0000000..8b4cab1
+--- /dev/null
++++ include/experiments/files.php
+@@ -0,0 +1,82 @@
++<?php
++
++/*
++ * Get the full path for the directory containing the user personal file
++ */
++function expfiles_getuserdir()
++{
++    $uid = CWebUser::$data['userid'];
++    $dir = $GLOBALS['GPLMT_FILES_DIR'].strval($uid).'/';
++    if(!file_exists($dir)) mkdir($dir);
++    return $dir;
++}
++
++/*
++ * Returns an array with the names of files inside the user personal directory
++ */
++function expfiles_getuserfiles()
++{
++    $dirpath = expfiles_getuserdir();
++    
++    $res = scandir($dirpath);
++    $res = array_diff($res, array('.', '..'));
++    return $res;
++}
++
++/*
++ * Given a file name for a new file to be uploaded, returns a full path 
++ * with the same or modified filename if already exists
++ */
++function expfiles_getnewfilepath($filename = 'new')
++{
++    $filename = exp_cleanfilename($filename);
++    $dirpath = expfiles_getuserdir();
++    
++    $parts = explode('.', $filename);
++    $orig = $parts[0];
++    
++    $counter = 0;
++    while(file_exists($dirpath.implode('.', $parts)))
++    {
++        $parts[0] = $orig.strval($counter);
++        $counter++;
++    }
++    
++    return $dirpath.implode('.', $parts);
++}
++
++function expfiles_delete($filename)
++{
++    $filename = exp_cleanfilename($filename);
++    $fullpath = expfiles_getuserdir().$filename;
++    if(file_exists($fullpath)) unlink($fullpath);
++    return true;
++}
++
++function expfiles_download($filename)
++{
++    $filename = basename($filename);
++    $fullpath = expfiles_getuserdir().$filename;
++    if(!file_exists($fullpath))
++    {
++        error("File doesn't exist");
++        return false;
++    }
++    
++    $size = filesize($fullpath);
++    $mime_type="application/force-download";
++    
++    //@ob_end_clean();
++    
++    header('Content-Type: ' . $mime_type);
++    header('Content-Disposition: attachment; filename="'.$filename.'"');
++    header("Content-Transfer-Encoding: binary");
++    header('Accept-Ranges: bytes');
++    header("Cache-control: private");
++    header('Pragma: private');
++    header('Content-Length: ' . $size);
++    ob_clean();
++    flush();
++    readfile($fullpath); 
++    exit;
++}
+diff --git include/experiments/inc.php include/experiments/inc.php
+new file mode 100644
+index 0000000..913e4e1
+--- /dev/null
++++ include/experiments/inc.php
+@@ -0,0 +1,70 @@
++<?php
++
++require_once dirname(__FILE__).'/conf.php';
++require_once dirname(__FILE__).'/db.php';
++require_once dirname(__FILE__).'/tasklist.php';
++require_once dirname(__FILE__).'/run.php';
++require_once dirname(__FILE__).'/files.php';
++require_once dirname(__FILE__).'/config.php';
++require_once dirname(__FILE__).'/nodes.php';
++require_once dirname(__FILE__).'/targets.php';
++
++define('EXP_OK', '0');
++define('EXP_ERR_GPLMT_DIR', '1');
++define('EXP_ERR_PERMISSION', '2');
++define('EXP_ERR_INVALID_TARGET', '3');
++define('EXP_ERR_UNKOWN', '100');
++
++function exp_errorstring($err)
++{
++    switch($err)
++    {
++        case EXP_OK:
++            return 'No errors';
++        case EXP_ERR_GPLMT_DIR:
++            return 'Could not verify GPLMT files, please make sure that they 
exist and write permissions are enabled';
++        case EXP_ERR_PERMISSION:
++            return 'Permission error';
++        case EXP_ERR_INVALID_TARGET:
++            return 'Invalid target';
++        case EXP_ERR_UNKOWN:
++        default:
++            return 'Unknown error';
++    }
++}
++
++function exp_cleanfilename($filename)
++{
++    return preg_replace("/[^a-z0-9\.]/", "", strtolower($filename));
++}
++
++
++function exp_gettargets()
++{
++    $cmd = 'python '.$GLOBALS['GPLMT_DIR'].'gplmt/Targets.py';
++    $res = array();
++    exec($cmd, $res);
++    return $res;
++}
++
++function exp_verifygplmtdir()
++{
++    if(!file_exists($GLOBALS['GPLMT_DIR'].'gplmt.py'))
++    {
++        error('GPLMT path invalid!');
++        return false;
++    }
++    
++    $old = umask(0);
++    if(!file_exists($GLOBALS['GPLMT_TASKLISTS_DIR'])) 
mkdir($GLOBALS['GPLMT_TASKLISTS_DIR']);
++    if(!file_exists($GLOBALS['GPLMT_CONF_DIR'])) 
mkdir($GLOBALS['GPLMT_CONF_DIR']);
++    if(!file_exists($GLOBALS['GPLMT_NODES_DIR'])) 
mkdir($GLOBALS['GPLMT_NODES_DIR']);
++    if(!file_exists($GLOBALS['GPLMT_RESULTS_DIR'])) 
mkdir($GLOBALS['GPLMT_RESULTS_DIR']);
++    if(!file_exists($GLOBALS['GPLMT_FILES_DIR'])) 
mkdir($GLOBALS['GPLMT_FILES_DIR']);
++    umask($old);
++    
++    return true;
++}
++
++exp_verifygplmtdir();
++expconfig_verifyuserconfig();
+diff --git include/experiments/nodes.php include/experiments/nodes.php
+new file mode 100644
+index 0000000..6d752bf
+--- /dev/null
++++ include/experiments/nodes.php
+@@ -0,0 +1,88 @@
++<?php
++
++function expnodes_getbyrunid($run_id)
++{
++    $run_id = zbx_dbstr($run_id);
++    
++    $sql = "SELECT exp_host.hostid, exp_host.host
++            FROM exp_runnode, exp_host
++            WHERE exp_runnode.hostid = exp_host.hostid
++            AND exp_runnode.runid = $run_id";
++    
++    return DBfetchArray(DBselect($sql));
++}
++
++function expnodes_writefile($nodes, $run_id)
++{
++    $nodes_file = $GLOBALS['GPLMT_NODES_DIR'].$run_id;
++    
++    $f = fopen($nodes_file, 'w+');
++    foreach($nodes as $n) fwrite($f, "$n\n");
++    fclose($f);
++}
++
++function expnodes_gethosts($target)
++{
++    $userid = CWebUser::$data['userid'];
++    return expdb_select('exp_host', array('userid' => $userid, 'target' => 
$target));
++}
++
++function expnodes_gethostbyid($hostid)
++{
++    $res = expdb_select('exp_host', array('hostid' => $hostid));
++    if(count($res) == 0) return null;
++    return $res[0];
++}
++
++function expnodes_gethostinterface($hostid)
++{
++    $h = API::Host()->get(array(
++        'hostids' => $hostid,
++        'output' => array(),
++        'selectInterfaces' => API_OUTPUT_EXTEND
++    ));
++    
++    if(count($h) == 0) return '';
++    foreach($h[0]['interfaces'] as $i)
++    {
++        if($i['main'] == 1)
++        {
++            if($i['useip'] == 1) return $i['ip'];
++            else return $i['dns'];
++        }
++    }
++}
++
++function expnodes_getzabbixnodes()
++{
++    $hosts = API::Host()->get(array(
++        'output' => array('hostid', 'host'),
++        'selectInterfaces' => API_OUTPUT_EXTEND
++    ));
++    
++    $nodes = array();
++    
++    foreach($hosts as $h)
++    {
++        $n = array();
++        $n['hostid'] = $h['hostid'];
++        $n['host'] = $h['host'];
++        
++        foreach($h['interfaces'] as $i)
++        {
++            if($i['main'] == 1)
++            {
++                $n['interfaceid'] = $i['interfaceid'];
++                if($i['useip'] == 1) $n['interface'] = $i['ip'];
++                else $n['interface'] = $i['dns'];
++                
++                break;
++            }
++        }
++        
++        $nodes[] = $n;
++    }
++    
++    return $nodes;
++}
++
+diff --git include/experiments/run.php include/experiments/run.php
+new file mode 100644
+index 0000000..3c47a6c
+--- /dev/null
++++ include/experiments/run.php
+@@ -0,0 +1,601 @@
++<?php
++
++define('EXP_STATUS_FAILED', -1);
++define('EXP_STATUS_NOT_STARTED', 0);
++define('EXP_STATUS_RUNNING', 1);
++define('EXP_STATUS_DONE_WITH_ERRORS', 2);
++define('EXP_STATUS_AWAITING_MONITORING', 3);
++define('EXP_STATUS_DONE_SUCCESSFULLY', 10);
++
++function exprun_getstatusstring($status)
++{
++    switch($status)
++    {
++        case -1:
++            return "Failed";
++        case 0:
++            return "Not started";
++        case 1:
++            return "Running";
++        case 2:
++            return "Done with errors";
++        case 3:
++            return "Waiting for monitoring to start";
++        case 10:
++            return "Done successfully";
++        default:
++            return "Undefined status";
++    }
++}
++
++function exprun_getall($extended = false, $string_status = true)
++{
++    exprun_updateresults(); //update database with any new results
++
++    $where['userid'] = intval(CWebUser::$data['userid']);
++
++    // get all my runs
++    $res = expdb_select('exp_run', $where);
++    
++    // add additional information to each run
++    for($i = 0; $i < sizeof($res); $i++)
++    {
++        // select run nodes
++        $sql = "SELECT exp_runnode.*, exp_host.host as interface FROM 
exp_runnode, exp_host
++                WHERE exp_runnode.runid = ".$res[$i]['runid']."
++                AND exp_runnode.hostid = exp_host.hostid
++                ORDER BY exp_runnode.status DESC, exp_runnode.percentage 
DESC, exp_host.host ASC";
++        $nodes = DBfetchArray(DBselect($sql));
++        
++        // replace status code with status string
++        if($string_status)
++        {
++            $res[$i]['status'] = exprun_getstatusstring($res[$i]['status']);
++            for($j = 0; $j < sizeof($nodes); $j++)
++            {
++                $nodes[$j]['status'] = 
exprun_getstatusstring($nodes[$j]['status']);
++            }
++        }
++        
++        // attach run nodes ot run
++        $res[$i]['nodes'] = $nodes;
++        
++        // if monitor was enabled, get zabbix host group id
++        $monitor = exprun_getmonitorrecord($res[$i]['runid']);
++        if($monitor)
++            $res[$i]['hostgroupid'] = $monitor['hostgroupid'];
++        
++        // get tasklist name if used
++        if($res[$i]['usetasklist'])
++        {
++            $sql = "SELECT name FROM exp_tasklist WHERE tasklistid = 
".$res[$i]['tasklistid'];
++            $tasklistres = DBfetchArray(DBselect($sql));
++            $res[$i]['tasklist'] = $tasklistres[0]['name'];
++        }
++    }
++    
++    return $res;
++}
++
++function exprun_updateresults()
++{
++    $running = expdb_select('exp_run', array('status' => EXP_STATUS_RUNNING));
++    foreach($running as $r)
++    {
++        $updates = exprun_parseresult($r['runid']);
++        expdb_update('exp_run', array('status' => $updates['status'], 
'percentage' => $updates['percentage']), array('runid' => $r['runid']));
++        foreach($updates['nodes_results'] as $nr)
++        {
++            expdb_update('exp_runnode',
++                array('status' => $nr['status'], 'percentage' => 
$nr['percentage'], 'log' => $nr['log']),
++                array('runid' => $r['runid'], 'hostid' => $nr['hostid']));
++        }
++        //if status moved from running to something else, stop monitoring
++        if($updates['status'] != EXP_STATUS_RUNNING)
++            exprun_stopmonitor($r['runid']);
++    }
++}
++
++function exprun_pidrunning($pid)
++{
++    $cmd = "ps --no-headers -p ".$pid;
++    $res = exec($cmd);
++    return !empty($res);
++}
++
++function exprun_calculatestatus($percentage, $running, $failure)
++{
++    if($percentage < 100) $status = ($running) ? EXP_STATUS_RUNNING : 
EXP_STATUS_FAILED;
++    else $status = ($failure) ? EXP_STATUS_DONE_WITH_ERRORS : 
EXP_STATUS_DONE_SUCCESSFULLY;
++    return $status;
++}
++
++function exprun_parseresult($run_id)
++{
++    $prog = 0;
++    $total = 1;
++    $failure = false;
++    $nodes_results = array();
++    
++    //Read metadata
++    $meta = exprun_getbyid($run_id);
++    
++    //Check if the process is already running
++    $running = exprun_pidrunning($meta['pid']);
++
++    $results_file = $GLOBALS['GPLMT_RESULTS_DIR'].$run_id;
++    if(file_exists($results_file))
++    {
++        //Read nodes from DB
++        $nodes = expnodes_getbyrunid($run_id);
++
++        //Read loaded tasks (if available)
++        if($meta['usetasklist'])
++            $tasks = exec('grep -Po "(?<=Loaded )\d+(?= tasks)" 
'.$results_file);
++        else
++            $tasks = 1;
++        if(!empty($tasks))
++        {
++            $tasks = intval($tasks);
++
++            $total = count($nodes) * $tasks;
++
++            //for each node, calculate progress from result output    
++            foreach($nodes as $n)
++            {
++                $node_failure = false;
++                $interface = $n['host'];
++
++                $res = array();
++                exec('grep -Po "'.$interface.'\s*\| .* \| \K.*" 
'.$results_file, $res); //final result
++                if(count($res) > 0)
++                {
++                    if(trim($res[0]) != 'success')
++                    {
++                        $failure = true;
++                        $node_failure = true;
++                    }
++                    $node_prog = $tasks;
++                }
++                else
++                {
++                    //tasks completed for node
++                    $tasks_completed = array();
++                    exec('grep -Po "'.$interface.' : Task \'.*\' completed" 
'.$results_file, $tasks_completed);
++                    $node_prog = count($tasks_completed);
++                }
++                
++                //get all node logs
++                $node_log_arr = array();
++                exec("grep -E '^$interface' $results_file", $node_log_arr);
++                $node_log = implode("\n", $node_log_arr);
++                
++                $node_perc = $node_prog * 100 / $tasks;
++                $nodes_results[] = array('status' => 
exprun_calculatestatus($node_perc, $running, $node_failure),
++                                    'percentage' => ($running) ? $node_perc : 
100,
++                                    'log' => $node_log,
++                                    'hostid' => $n['hostid']);
++                $prog += $node_prog;
++            }
++        }
++    }
++    
++    $perc = $prog * 100 / $total; //percentage done
++    $status = exprun_calculatestatus($perc, $running, $failure); //total 
status
++    
++    return array('status' => $status, 'percentage' => ($running) ? $perc : 
100, 'nodes_results' => $nodes_results);
++}
++
++function exprun_new($target, $params, $usetasklist, $tasklist, $cmd, 
$monitor, $expname, $templates)
++{
++    if(!exp_verifygplmtdir()) return EXP_ERR_GPLMT_DIR;
++    if($usetasklist == 1 && exptasklist_allowed($tasklist) == 0) return 
EXP_ERR_PERMISSION;
++    
++    //create run record
++    $run_data = array();
++    $run_data['usetasklist'] = $usetasklist;
++    if($usetasklist == 1)
++        $run_data['tasklistid'] = $tasklist;
++    else
++        $run_data['command'] = $cmd;
++    $run_data['userid'] = intval(CWebUser::$data['userid']);
++    $run_data['target'] = $target;
++    
++    $run_id = expdb_insert('exp_run', $run_data);
++
++    //create run-nodes records
++    switch($target)
++    {
++        case 'ssh':
++        case 'planetlab':
++        case 'hen':
++            $hostnames = array();
++            foreach($params as $h) //get hostnames and save to DB
++            {
++                $hostinfo = expnodes_gethostbyid($h); $hostnames[] = 
$hostinfo['host'];
++                expdb_insert('exp_runnode', array('runid' => $run_id, 
'hostid' => $h, 'target' => $target));
++            }
++            //write GPLMT nodes file
++            expnodes_writefile($hostnames, $run_id);
++            break;
++            
++        default: //invalid target
++            expdb_delete('exp_run', array('runid' => $run_id));
++            return EXP_ERR_INVALID_TARGET;
++    }
++    
++    if($monitor)
++    {
++        $res = exprun_initmonitor($run_id, $hostnames, $expname, $templates);
++        if(!$res)
++        {
++            exprun_delete($run_id);
++            return EXP_ERR_UNKOWN;
++        }
++    }
++    
++    exprun_gplmt($run_id, !$monitor);
++    
++    return EXP_OK;
++}
++
++function exprun_getbyid($run_id)
++{
++    $res = expdb_select('exp_run', array('runid' => $run_id));
++    return $res[0];
++}
++
++function exprun_rerun($run_id)
++{
++    $meta = exprun_getbyid($run_id);
++    if(exprun_pidrunning($meta['pid'])) return;
++
++    //restart monitoring
++    $monitor = exprun_remonitor($run_id);
++    
++    exprun_gplmt($run_id, !$monitor);
++}
++
++function exprun_checkpermission($run_id)
++{
++    if(CWebUser::$data['type'] == 3) return true;
++    
++    $res = expdb_select('exp_run', array('userid' => 
CWebUser::$data['userid'], 'runid' => $run_id));
++    
++    return (sizeof($res) > 0);
++}
++
++function exprun_interrupt($run_id)
++{
++    $meta = exprun_getbyid($run_id);
++    
++    if(!exprun_checkpermission($run_id)) return;
++    
++    $cmd = "kill -15 ".$meta['pid'];
++    exec($cmd);
++    
++    //stop monitoring
++    exprun_stopmonitor($run_id);
++}
++
++function exprun_delete($run_id)
++{
++    $meta = exprun_getbyid($run_id);    
++
++    //check permissions
++    if(!exprun_checkpermission($run_id)) return;
++    
++    //check if tool still running
++    if(exprun_pidrunning($meta['pid'])) return;
++
++    $n = $GLOBALS['GPLMT_NODES_DIR'].$run_id;
++    if(file_exists($n)) unlink($n);
++    $r = $GLOBALS['GPLMT_RESULTS_DIR'].$run_id;
++    if(file_exists($r)) unlink($r);
++    
++    //delete monitoring if set
++    if($monitor = exprun_getmonitorrecord($run_id))
++    {
++        // set host group permissions to full access for API delete
++        DB::update('rights', array(
++            array(
++                          'values' => array('permission' => PERM_READ_WRITE),
++                          'where' => array('groupid' => 
$monitor['usergroupid'], 'id' => $monitor['hostgroupid'])
++          )));
++        
++        // delete hosts
++        $hosts = API::Host()->get(array(
++            'groupids' => array($monitor['hostgroupid'])
++            ));
++        API::Host()->delete($hosts);
++
++        //delete hostgroup
++        DB::delete('groups', array('groupid' => $monitor['hostgroupid']));
++        
++        //delete monitor record
++        expdb_delete('exp_monitor', array('runid' => $run_id));
++    }
++    
++    expdb_delete('exp_run', array('runid' => $run_id));
++    expdb_delete('exp_runnode', array('runid' => $run_id));
++}
++
++function exprun_verifyid($run_id)
++{
++    $res = expdb_select('exp_run', array('runid' => $run_id));
++    return (sizeof($res) > 0);
++}
++
++function exprun_gplmt($run_id, $run_gplmt)
++{
++    $run_data = exprun_getbyid($run_id);
++    if($run_data['usetasklist'])
++        $tasklist_data = exptasklist_getbyid($run_data['tasklistid']);
++    
++    //compose and run command
++    $cmd = 'python -u '.$GLOBALS['GPLMT_DIR'].'gplmt.py -V'; // GPLMT
++    $cmd .= ' -c '.$GLOBALS['GPLMT_CONF_DIR'].CWebUser::$data['userid']; // 
Conf file
++    $cmd .= ' -n '.$GLOBALS['GPLMT_NODES_DIR'].$run_id; // Nodes file
++    if($run_data['target'] == 'ssh')
++        $cmd .= ' -t remote_ssh';
++    else
++        $cmd .= ' -t '.$run_data['target'];
++    if($run_data['usetasklist'])
++        $cmd .= ' -l 
'.$GLOBALS['GPLMT_TASKLISTS_DIR'].$tasklist_data['fsname']; // Tasklist file
++    else
++        $cmd .= " -C '".$run_data['command']."'"; // Command to run
++    $cmd .= ' > '.$GLOBALS['GPLMT_RESULTS_DIR'].$run_id; // Results file
++    $cmd .= ' 2>&1 & echo $!'; // Redirect stderr, run in background and get 
pid
++    
++    if($run_gplmt)
++    {
++        $pid = system($cmd);
++        expdb_update("exp_run", array('fullcommand' => $cmd, 'pid' => $pid, 
'status' => EXP_STATUS_RUNNING, 'startedon' => date('Y-m-d H:i:s')), 
array('runid' => $run_id));
++    }
++    else // in case we don't want to run GPLMT now, running will be delayed 
until monitoring is UP
++    {
++        // the command should include changing permissions of the results 
file for www-data to read it
++        //$cmd .= ' & chmod 777 '.$GLOBALS['GPLMT_RESULTS_DIR'].$run_id;
++        $cmd = 'touch '.$GLOBALS['GPLMT_RESULTS_DIR'].$run_id.' & chmod 777 
'.$GLOBALS['GPLMT_RESULTS_DIR'].$run_id.' & '.$cmd;
++        expdb_update("exp_run", array('fullcommand' => $cmd, 'status' => 
EXP_STATUS_AWAITING_MONITORING), array('runid' => $run_id));
++    }
++}
++
++
++/**
++* Monitoring functions
++*/
++
++function exprun_remonitor($runid)
++{
++    $monitor = exprun_getmonitorrecord($runid);
++    if(!$monitor) return false;
++    
++    //get hosts
++    $hosts = API::Host()->get(
++            array('groupids' => array($monitor['hostgroupid']))
++        );
++    $hostids = array();
++    foreach($hosts as $h)
++        $hostids[] = $h['hostid'];
++    
++    //enable hosts
++    if(count($hostids) > 0)
++    {
++        $hostids_str = implode(',', $hostids);
++        $sql = "UPDATE hosts SET status = 0 WHERE hostid in ($hostids_str)";
++        DBexecute($sql);
++    }
++    
++    return true;
++}
++
++function exprun_getmonitorrecord($runid)
++{
++    $monitor = expdb_select('exp_monitor', array('runid' => $runid));
++    return (count($monitor) > 0) ? $monitor[0] : null;
++}
++
++/*
++* The cases when this function should be called:
++* 1- After the experiment is done
++* 2- When the experiment is interrupted
++*/
++function exprun_stopmonitor($runid)
++{
++    //get monitor record
++    $monitor = exprun_getmonitorrecord($runid);
++    if(!$monitor) return;
++    
++    //stop monitoring
++    //get hosts
++    $hosts = API::Host()->get(
++            array('groupids' => array($monitor['hostgroupid']))
++        );
++    $hostids = array();
++    foreach($hosts as $h)
++        $hostids[] = $h['hostid'];
++    //get items
++    $items = API::Item()->get(
++            array('hostids' => $hostids)
++        );
++    $itemids = array();
++    foreach($items as $i)
++        $itemids[] = $i['itemid'];
++    
++    //disable hosts
++    if(count($hostids) > 0)
++    {
++        $hostids_str = implode(',', $hostids);
++        $sql = "UPDATE hosts SET status = 1 WHERE hostid in ($hostids_str)";
++        DBexecute($sql);
++    }
++    
++    //truncate history and trends to match the last modified datetime
++    $results_file = $GLOBALS['GPLMT_RESULTS_DIR'].$runid;
++    if(count($itemids) > 0 && file_exists($results_file))
++    {
++        $stoptime = filemtime($results_file); //last modified time
++        $history_tables = array('history', 'history_log', 'history_str', 
'history_str_sync', 'history_sync', 'history_text', 'history_uint', 
'history_uint_sync', 'proxy_history', 'trends', 'trends_uint');
++        $itemids = implode(',', $itemids);
++        foreach($history_tables as $ht)
++        {
++            $sql = "DELETE FROM $ht WHERE itemid IN ($itemids) AND clock > 
$stoptime";
++            DBexecute($sql);
++        }
++    }
++}
++
++function exprun_initmonitor($runid, $hostnames, $expname, $templates)
++{
++    //Inserting records manually instead of API to circumvent permission 
issues (e.g. only super admin can create host groups..etc)
++
++    $userid = intval(CWebUser::$data['userid']);
++    $username = CWebUser::$data['alias'];
++
++    // Create host group
++    $hostgroupname = "Experiment $expname";
++    $counter = 1;
++    while(count(DB::Find('groups', array('name' => $hostgroupname))) > 0)
++    {
++        $hostgroupname = "Experiment $expname ($counter)";
++        $counter++;
++    }
++    
++    $hostgroupid = DB::insert('groups', array(array(
++        'name' => $hostgroupname,
++        'internal' => 0)));
++    $hostgroupid = $hostgroupid[0];
++    
++    // Get usrgrpid for this user from any previous monitor record
++    $usrgrpid = 0;
++    $res = expdb_select('exp_monitor', array('userid' => $userid));
++    if(count($res) > 0) $usrgrpid = $res[0]['usergroupid'];
++    
++    // If no usrgrp for user, create it and assign the user to it
++    
++    if(!$usrgrpid)
++    {
++        $usrgrpname = "$username experiment group";
++        $counter = 1;
++        while(count(DB::Find('usrgrp', array('name' => $usrgrpname))) > 0)
++        {
++            $usrgrpname = "$username experiment group - $counter";
++            $counter++;
++        }
++        
++        $usrgrpid = DB::insert('usrgrp', array(array(
++            'name' => $usrgrpname,
++            'gui_access' => 0,
++            'users_status' => 0,
++            'debug_mode' => 0
++        )));
++        $usrgrpid = $usrgrpid[0];
++        
++        DB::insert('users_groups', array(array(
++            'usrgrpid' => $usrgrpid,
++            'userid' => $userid
++        ))); 
++    }
++    
++    // Grant permission for host group to user group (full access for now to 
add hosts)
++    $rightid = DB::insert('rights', array(array(
++        'groupid' => $usrgrpid,
++        'permission' => PERM_READ_WRITE,
++        'id' => $hostgroupid
++    )));
++    $rightid = $rightid[0];
++    
++    // - Create nodes
++    
++    foreach($hostnames as $host)
++    {
++        $hostname = "$host - $expname";
++        $counter = 1;
++        while(count(DB::Find('hosts', array('name' => $hostname))) > 0)
++        {
++            $hostname = "$host - $expname - $counter";
++            $counter++;
++        }
++    
++        $h = array(
++                  'host' => $hostname,
++                  'name' => $hostname,
++                  'groups' => zbx_toObject(array($hostgroupid => 
$hostgroupid), 'groupid'),
++                  'templates' => zbx_toObject(array_keys($templates), 
'templateid'),
++                  'interfaces' => array(1 => array('type' => 1, 'ip' => '', 
'dns' => $host, 'useip' => 0, 'port' => 10050, 'main' => 1)),
++          );
++          
++          API::Host()->create($h);
++    }
++    
++    // Update permissions to readonly
++    DB::update('rights', array(
++        array(
++                      'values' => array('permission' => PERM_READ),
++                      'where' => array('rightid' => $rightid)
++      )));
++    
++    // Create monitor record
++    expdb_insert('exp_monitor', array(
++        'runid' => $runid,
++        'userid' => $userid,
++        'hostgroupid' => $hostgroupid,
++        'usergroupid' => $usrgrpid
++    ));
++    
++    return true;
++}
++
++/*
++* Given a host group ID
++* Prints to stdout history of the hosts as csv
++* It is expected that before calling this function, the content type headers 
are set correctly
++*/
++function exp_getmonitorhistory($hostgroupid)
++{
++    //Initializations
++    $historytables = array('history', 'history_str', 'history_log', 
'history_uint', 'history_text');
++    $stdout = fopen('php://output','w');
++    
++    //print columns definition
++    echo "#hostname,itemname,clock,value,unit\n";
++    
++    // Get all hosts belonging to the hostgroup
++    $sql = "SELECT hostid FROM hosts_groups WHERE groupid = 
".zbx_dbstr($hostgroupid);
++    $res = DBfetchArray(DBselect($sql));
++    
++    foreach($res as $host)
++    {
++        // Get hostname
++        $sql = "SELECT host FROM hosts WHERE hostid = ".$host['hostid'];
++        $res = DBfetchArray(DBselect($sql));
++        if(count($res) == 0) //invalid hostid?
++            continue;
++        $hostname = $res[0]['host'];
++        
++        // Get all items configured on this host
++        $sql = "SELECT itemid, name, key_, value_type, units
++            FROM items WHERE hostid = ".$host['hostid'];
++        $items = DBfetchArray(DBselect($sql));
++        
++        foreach($items as $item)
++        {
++            // Get history of this item from each possible table
++            foreach($historytables as $table)
++            {
++                $sql = "SELECT clock, value FROM $table
++                    WHERE itemid = ".$item['itemid'].
++                    " ORDER BY clock ASC";
++                $cursor = DBselect($sql);
++                while($row = DBfetch($cursor))
++                {
++                    $fullrow = array($hostname, $item['name'], $row['clock'], 
$row['value'], $item['units']);
++                    fputcsv($stdout, $fullrow);
++                    unset($fullrow);
++                    unset($row);
++                }
++            }
++        }
++    }
++}
+diff --git include/experiments/targets.php include/experiments/targets.php
+new file mode 100644
+index 0000000..e599500
+--- /dev/null
++++ include/experiments/targets.php
+@@ -0,0 +1,183 @@
++<?php
++
++require_once 'XML/RPC2/Client.php';
++
++$exp_targetlist = array(
++    'SSH' => 'ssh',
++    'Planetlab' => 'planetlab',
++    'HEN' => 'hen');
++
++/*
++ * Planetlab
++ */
++
++function exppl_getauth()
++{
++    $pl_user = expconfig_getconfigbyname('username');
++    if(!$pl_user) fatal_error('Please specify planetlab username in config');
++    $pl_pass = expconfig_getconfigbyname('password');
++    if(!$pl_pass) fatal_error('Please specify planetlab password in config');
++    
++    return array(
++        "AuthMethod" => 'password',
++        "Username" => $pl_user,
++        "AuthString" => $pl_pass
++        );
++}
++
++function exppl_getclient()
++{
++    $pl_api = expconfig_getconfigbyname('api_url');
++    if(!$pl_api) fatal_error('Please specify planetlab API in config');
++    
++    return XML_RPC2_Client::create($pl_api, array('sslverify' => false));
++}
++
++function exppl_getslicename()
++{
++    $pl_slice = expconfig_getconfigbyname('slice');
++    if(!$pl_slice) fatal_error('Please specify planetlab slice in config');
++    return $pl_slice;
++}
++
++function exppl_getAvailableNodes($page_offset, $page_size, $hostfilter = null)
++{
++    $page_offset = intval($page_offset);
++    $page_size = intval($page_size);
++
++    $pl_slice = exppl_getslicename();
++    $auth = exppl_getauth();
++    $client = exppl_getclient();
++    
++    //get node IDs in slice (for negation)
++    try
++    {
++        $res = $client->GetSlices($auth, $pl_slice, array('node_ids')); 
$node_ids = $res[0]['node_ids'];
++    }
++    catch (XML_RPC2_FaultException $e)
++    {
++        fatal_error($e->getFaultCode() . ' : ' . $e->getFaultString());
++    }
++    
++    $filter = array('~node_id' => $node_ids,
++                    '-SORT' => 'hostname',
++                    '-OFFSET' => $page_offset,
++                    '-LIMIT' => $page_size);
++    if($hostfilter) $filter['hostname'] = "*$hostfilter*";
++    
++    try
++    {
++        return $client->GetNodes($auth, $filter, array('hostname', 
'node_id'));
++    }
++    catch (XML_RPC2_FaultException $e)
++    {
++        fatal_error($e->getFaultCode() . ' : ' . $e->getFaultString());
++    }
++}
++
++function exppl_getSliceNodes()
++{
++    $pl_slice = exppl_getslicename();
++    $auth = exppl_getauth();
++    $client = exppl_getclient();
++
++    //get node IDs
++    try
++    {
++        $res = $client->GetSlices($auth, $pl_slice, array('node_ids')); 
$node_ids = $res[0]['node_ids'];
++    }
++    catch (XML_RPC2_FaultException $e)
++    {
++        fatal_error($e->getFaultCode() . ' : ' . $e->getFaultString());
++    }
++    
++    //get node hostnames + IDs
++    try
++    {
++        $res = $client->GetNodes($auth, $node_ids, array('hostname', 
'node_id'));
++    }
++    catch (XML_RPC2_FaultException $e)
++    {
++        fatal_error($e->getFaultCode() . ' : ' . $e->getFaultString());
++    }
++    $res = exppl_updateSliceNodesDB($res);
++    return $res;
++}
++
++function exppl_updateSliceNodes($nodes)
++{
++    $pl_slice = exppl_getslicename();
++    $auth = exppl_getauth();
++    $client = exppl_getclient();
++    
++    try
++    {
++        $client->UpdateSlice($auth, $pl_slice, array('nodes' => 
array_map('intval', array_values($nodes))));
++    }
++    catch (XML_RPC2_FaultException $e)
++    {
++        fatal_error($e->getFaultCode() . ' : ' . $e->getFaultString());
++    }
++}
++
++function exppl_updateSliceNodesDB($nodes)
++{
++    if(!is_array($nodes)) return;
++    
++    $userid = CWebUser::$data['userid'];
++    
++    // No delete so as not to break previous runs
++    // Insert new hosts not seen before
++    
++    for($i = 0; $i < count($nodes); $i++)
++    {
++        if(!exppl_getHostByPLNodeId($nodes[$i]['node_id'])) //Does not exist
++            $nodes[$i]['hostid'] = expdb_insert('exp_host', array('userid' => 
$userid, 'host' => $nodes[$i]['hostname'], 'target' => 'planetlab', 'pl_nodeid' 
=> $nodes[$i]['node_id']));
++        else
++            { $res = exppl_getHostByPLNodeId($nodes[$i]['node_id']); 
$nodes[$i]['hostid'] = $res['hostid']; }
++    }
++    
++    return $nodes;
++}
++
++function exppl_getHostByPLNodeId($pl_nodeid)
++{
++    $res = expdb_select('exp_host', array('pl_nodeid' => $pl_nodeid));
++    if(count($res) == 0) return null;
++    return $res[0];
++}
++
++/*
++ * General
++ */
++
++function exptarget_updatehosts($hostlist, $target)
++{
++    if(!is_array($hostlist)) return;
++    
++    $userid = CWebUser::$data['userid'];
++    
++    $old_hostlist = array();
++    $new_hostlist = array();
++    foreach($hostlist as $h)
++    {
++        $hc = trim($h);
++        if(!$hc) continue;
++        if(is_numeric($hc))
++            $old_hostlist[] = $hc;
++        else //added hosts value is the host itself not an ID
++            $new_hostlist[] = $hc;
++    }
++
++    //look for deleted hosts    
++    $sql = 'DELETE FROM exp_host
++        WHERE userid = '.$userid
++        .' AND target = "'.$target.'"';
++    if(count($old_hostlist) > 0)
++        $sql .= ' AND hostid NOT IN ('.implode(',', $old_hostlist).')';
++    DBexecute($sql);
++    
++    //look for new hosts
++    foreach($new_hostlist as $h)
++        expdb_insert('exp_host', array('userid' => $userid, 'host' => $h, 
'target' => $target));
++}
+diff --git include/experiments/tasklist.php include/experiments/tasklist.php
+new file mode 100644
+index 0000000..da2fcfb
+--- /dev/null
++++ include/experiments/tasklist.php
+@@ -0,0 +1,295 @@
++<?php
++
++require_once dirname(__FILE__).'/files.php';
++
++//default XML elements (for creating empty nods)
++$exptasklist_defaults = array();
++$exptasklist_defaults['sequence'] = new SimpleXMLElement('<sequence 
name=""></sequence>');
++$exptasklist_defaults['run'] = new SimpleXMLElement('<run 
name=""><command></command><arguments></arguments><timeout>0</timeout><expected_return_code>0</expected_return_code><expected_output></expected_output><stop_on_fail>false</stop_on_fail></run>');
++$exptasklist_defaults['run_per_host'] = new SimpleXMLElement('<run_per_host 
name=""><command_file></command_file><output_prefix></output_prefix><timeout>0</timeout><expected_return_code>0</expected_return_code><expected_output></expected_output><stop_on_fail>false</stop_on_fail></run_per_host>');
++$exptasklist_defaults['put'] = new SimpleXMLElement('<put 
name=""><source></source><destination></destination><stop_on_fail>false</stop_on_fail></put>');
++$exptasklist_defaults['get'] = new SimpleXMLElement('<get 
name=""><source></source><destination>./</destination><stop_on_fail>false</stop_on_fail></get>
 ');
++
++function exptasklist_addall()
++{
++    $sql = "SELECT * FROM exp_tasklist";
++    $indb = DBfetchArrayAssoc(DBSelect($sql), 'fsname');
++    
++    $indir = scandir($GLOBALS['GPLMT_TASKLISTS_DIR']);
++    
++    $counter = 0;
++    foreach($indir as $i)
++    {
++        if(substr($i, -4) != '.xml') continue;
++        if(isset($indb[$i])) continue;
++        $name = str_replace('_', ' ', $i);
++        $name = str_replace('.xml', '', $name);
++        
++        expdb_insert('exp_tasklist', array('name' => $name, 'fsname' => $i, 
'userid' => CWebUser::$data['userid'], 'shared' => 1));
++        $counter++;
++    }
++    return $counter;
++}
++
++function exptasklist_getall($editable = false)
++{
++    $sql = "SELECT exp_tasklist.*, CONCAT_WS(' ', users.name, users.surname) 
as username
++            FROM exp_tasklist INNER JOIN users ON exp_tasklist.userid = 
users.userid";
++    if(!(CWebUser::$data['type'] == 3)) //not super admin
++    {
++        $sql .= ' WHERE exp_tasklist.userid = '.CWebUser::$data['userid'];
++        if(!$editable)
++            $sql .= ' OR exp_tasklist.shared = 1';
++    }
++    
++    return DBfetchArray(DBselect($sql));
++}
++
++function exptasklist_getbyid($tasklistid)
++{
++    $res = expdb_select('exp_tasklist', array('tasklistid' => $tasklistid));
++    if(count($res) == 0) return null;
++    return $res[0];
++}
++
++function exptasklist_getcontent($tasklistid)
++{
++    $tl_row = exptasklist_getbyid($tasklistid);
++    if(!$tl_row) return null;
++    $file = $GLOBALS['GPLMT_TASKLISTS_DIR'].$tl_row['fsname'];
++    if(!file_exists($file)) return null;
++    return file_get_contents($file);
++}
++
++/**
++ * Given a tasklist id, returns 0, 1 or 2 for No access, read, read/write 
respectively
++ *
++ * @return int
++ */
++function exptasklist_allowed($tasklistid)
++{
++    $tl_row = exptasklist_getbyid($tasklistid);
++    if(!$tl_row) return 0;
++    if(CWebUser::$data['type'] == 3 || $tl_row['userid'] == 
CWebUser::$data['userid']) return 2;
++    if($tl_row['shared']) return 1;
++    return 0;
++}
++
++function exptasklist_delete($tid)
++{
++    $meta = exptasklist_getbyid($tid);
++    if(!$meta)
++    {
++        error("Invalid tasklist ID");
++        return false;
++    }
++    $fullFileName = $GLOBALS['GPLMT_TASKLISTS_DIR'].$meta['fsname'];
++    
++    //delete from DB
++    expdb_delete('exp_tasklist', array('tasklistid' => $tid));
++    
++    //delete file
++    if(file_exists($fullFileName)) unlink($fullFileName);
++    
++    return true;
++}
++
++function exptasklist_sxmlappend(SimpleXMLElement $to, SimpleXMLElement $from)
++{
++    $toDom = dom_import_simplexml($to);
++    $fromDom = dom_import_simplexml($from);
++    $newDom = $toDom->appendChild($toDom->ownerDocument->importNode($fromDom, 
true));
++    return simplexml_import_dom($newDom);
++}
++
++function exptasklist_constructxml($data)
++{
++    global $exptasklist_defaults;
++    
++    $xml = new SimpleXMLElement('<?xml version="1.0" 
encoding="UTF-8"?><tasklist></tasklist>');
++    $xml->addAttribute('xsi:noNamespaceSchemaLocation', 
"../tasklist_schema.xsd", "http://www.w3.org/2001/XMLSchema-instance";);
++    $xml->addChild('options');
++
++    //name
++    if(empty($data['name']))
++    {
++        error("Missing name field");
++        return false;
++    }
++    $name = $data['name'];
++    $xml->addAttribute('name', $name);
++    
++    //target
++    /*if(!empty($data['target']))
++        $xml->options->addChild('target', $data['target']);*/
++
++    //log dir
++    if(!empty($data['logdir']))
++        $xml->options->addChild('log_dir', $data['logdir']);
++    
++    //index for node components
++    $nodesIndex = array();
++    
++    foreach($data as $k => $v)
++    {
++        $parts = explode('_', $k); // field name consists of field type + the 
path to the field (e.g. command_2_1)
++        $parts_count = count($parts);
++        if($parts_count == 1 || $parts_count > 3) continue;
++        
++        $field = str_replace('$', '_', $parts[0]);
++        $value = trim($v);
++        $index = implode('_', array_slice($parts, 1));
++        
++        if($field == 'type') //should be the first field in the node, its type
++        {
++            if(!array_key_exists($value, $exptasklist_defaults)) continue; 
//invalid type
++            
++            if($parts_count == 2) $parent = $xml;
++            else $parent = $nodesIndex[$parts[1]];
++            
++            $newXml = $exptasklist_defaults[$value];
++            if($value != 'sequence')
++            {
++                $newXml['id'] = $parts[$parts_count - 1]; //GPLMT doesn't 
accept ID in sequence but mandatory for others
++                $newXml['name'] = $newXml['id']; //Name is also mandatory, so 
we set it by the ID unless we get a name from the user later
++            }
++            $newXml['enabled'] = 'false'; //Disabled by default unless we get 
the enabled flag from form
++            
++            $nodesIndex[$index] = exptasklist_sxmlappend($parent, $newXml);
++            
++            
++            continue;
++        }
++        
++        if(!array_key_exists($index, $nodesIndex)) continue; //problem or 
data element that is not related to the XML
++        if($field == 'name' && empty($value)) continue;
++        
++        $subxml = $nodesIndex[$index];
++        $type = $subxml->getName();
++        
++        //validations:
++        switch($field)
++        {
++            //bool
++            case 'enabled': case 'stop_on_fail':
++                $value = strtolower($value);
++                if($value != 'yes' && $value != 'no')
++                {
++                    error("Value for $field should be true or false!");
++                    return false;
++                }
++                $value = ($value == 'yes') ? 'true' : 'false';
++                break;
++            
++            //int
++            case 'timeout': case 'expected_return_code':
++                if(!is_numeric($value))
++                {
++                    error("Value for $field should be an integer!");
++                    return false;
++                }
++                break;
++
++            //file
++            case 'source':
++                if($type == 'put')
++                {
++                    $value = exp_cleanfilename($value);
++                }
++                break;
++            case 'destination':
++                if($type == 'get')
++                {
++                    $value = './';
++                }
++                break;
++        }
++        
++        //writing values
++        switch($field)
++        {
++            //attributes
++            case 'enabled': case 'name':
++                $subxml[$field] = $value;
++                break;
++            
++            case 'command': case 'arguments': case 'timeout': case 
'expected_return_code': case 'expected_output':
++            case 'stop_on_fail': case 'command_file': case 'output_prefix': 
case 'source': case 'destination':
++                $subxml->$field = $value;
++                break;
++            
++            default:
++                error("Unknown field: $field");
++        }
++    }
++    
++    //save the resulting XML to file (formatted)
++    $dom = dom_import_simplexml($xml)->ownerDocument;
++    $dom->formatOutput = true;
++    return $dom->saveXML();
++}
++
++function exptasklist_add($data)
++{
++    $xml = exptasklist_constructxml($data);
++    if(!$xml) return false;
++    
++    //name
++    $name = $data['name'];
++    
++    //description
++    $description = empty($data['description']) ? '' : $data['description'];
++    
++    //shared
++    $shared = false;
++    $shared = (!empty($data['shared']) && ($data['shared'] == 'yes'));
++    
++    //create new fsname
++    $fsname = str_replace(' ', '_', $name);
++    $fsname = str_replace('\\', '_', $fsname);
++    $counter = 0;
++    while(file_exists($GLOBALS['GPLMT_TASKLISTS_DIR'].$fsname.'.xml'))
++    {
++        $fsname .= strval($counter);
++        $counter++;
++    }
++    $fsname .= '.xml';
++    
++    //user ID
++    $userid = CWebUser::$data['userid'];
++    
++    //save to file
++    file_put_contents($GLOBALS['GPLMT_TASKLISTS_DIR'].$fsname, $xml);
++    
++    //save to DB
++    expdb_insert('exp_tasklist',
++        array('name' => $name, 'description' => $description, 'fsname' => 
$fsname, 'userid' => $userid, 'shared' => intval($shared)));
++    
++    return true;
++}
++
++function exptasklist_update($tasklistid, $data)
++{
++    $meta = exptasklist_getbyid($tasklistid); //get task meta data from db
++    
++    $xml = exptasklist_constructxml($data);
++    if(!$xml) return false;
++    
++    //name
++    $name = $data['name'];
++    
++    //description
++    $description = empty($data['description']) ? '' : $data['description'];
++    
++    //shared
++    $shared = false;
++    $shared = (!empty($data['shared']) && ($data['shared'] == 'yes'));
++    
++    file_put_contents($GLOBALS['GPLMT_TASKLISTS_DIR'].$meta['fsname'], $xml);
++    
++    //update DB
++    expdb_update('exp_tasklist', array('name' => $name, 'description' => 
$description, 'shared' => intval($shared)),
++        array('tasklistid' => $tasklistid));
++    
++    return true;
++}
+diff --git include/menu.inc.php include/menu.inc.php
+index 15896ea..9b6379e 100644
+--- include/menu.inc.php
++++ include/menu.inc.php
+@@ -278,6 +278,38 @@ $ZBX_MENU = array(
+                       )
+               )
+       ),
++      'experiment' => array(
++              'label'                         => _('Experiments'),
++              'user_type'                     => USER_TYPE_ZABBIX_ADMIN,
++              'node_perm'                     => PERM_READ_WRITE,
++              'default_page_id'       => 0,
++              'pages' => array(
++                      array(
++                              'url' => 'execute.php',
++                              'label' => _('Deploy & Execute')
++                      ),
++                      array(
++                              'url' => 'results.php',
++                              'label' => _('Results')
++                      ),
++                      array(
++                              'url' => 'targets.php',
++                              'label' => _('Targets')
++                      ),
++                      array(
++                              'url' => 'tasklist.php',
++                              'label' => _('Tasklists')
++                      ),
++                      array(
++                              'url' => 'files.php',
++                              'label' => _('Files')
++                      ),
++                      array(
++                              'url' => 'conf.php',
++                              'label' => _('Configuration')
++                      )
++              )
++      ),
+       'login' => array(
+               'label'                                 => _('Login'),
+               'user_type'                             => 0,
+diff --git include/views/experiments.conf.php 
include/views/experiments.conf.php
+new file mode 100644
+index 0000000..0af85d5
+--- /dev/null
++++ include/views/experiments.conf.php
+@@ -0,0 +1,66 @@
++<?php
++
++$conf = $this->get('conf');
++
++$cWidget = new CWidget();
++
++$cForm = new CForm('post');
++$cTable = new CTableInfo();
++
++$current_section = '';
++foreach($conf as $c)
++{
++    if($c['section'] != $current_section)
++    {
++        $current_section = $c['section'];
++        $cTable->addRow(strtoupper($current_section));
++    }
++    
++    switch($c['type'])
++    {
++        case 'text': case 'integer':
++            $cInput = new CTextBox($c['configid'], $c['value']);
++            break;
++        
++        case 'password':
++            $cInput = new CPassBox($c['configid'], $c['value'], 20);
++            break;
++        
++        case 'boolean':
++            $cHidden = new CInput('hidden', $c['configid'], 'no');
++            $cChkbox = new CCheckBox($c['configid'], $c['value']);
++            $cInput = array($cHidden, $cChkbox);
++            break;
++        
++        case 'file':
++            $userfiles = expfiles_getuserfiles();
++            $selectedfile = '';
++            if(!empty($c['value'])) $selectedfile = basename($c['value']);
++            $cInput = new CComboBox($c['configid']);
++            $cInput->addItem('', '');
++            foreach($userfiles as $uf)
++                $cInput->addItem($uf, $uf, ($selectedfile == $uf)?'yes':null);
++            break;
++
++        case 'enum':
++            $options = expconfig_getenum($c['configid']);
++            $cInput = new CComboBox($c['configid']);
++            foreach($options as $o)
++                $cInput->addItem($o['value'], $o['label'], ($c['value'] == 
$o['value'])?'yes':null);
++            break;
++
++        default:
++            $cInput = new CLabel('Invalid type');
++            break;
++    }
++    
++    $help_image = new CImg('images/general/question_mark.png');
++    $help_image->attr('title', $c['description']);
++    
++    $cTable->addRow(array($c['label'], array($cInput, $help_image)));
++}
++$cTable->addRow(new CSubmit('update', 'Update'));
++
++$cForm->addItem($cTable);
++$cWidget->addItem($cForm);
++return $cWidget;
+diff --git include/views/experiments.execute.php 
include/views/experiments.execute.php
+new file mode 100644
+index 0000000..6840c0d
+--- /dev/null
++++ include/views/experiments.execute.php
+@@ -0,0 +1,163 @@
++<?php
++
++$targets = $this->get('targets');
++$data = $this->get('data');
++
++$currenttarget = isset($data['target']) ? $data['target'] : reset($targets);
++
++//Main Form
++$exec_frm = new CForm();
++$exec_frm->setName('web.experiment.execute.php.');
++$exec_frm->attr('id', 'mainfrm');
++
++//Main table
++$main_table = new CTable();
++
++//Row 1 - Targets
++$targets_cmb = new CComboBox('target');
++foreach($targets as $k => $v)
++    $targets_cmb->addItem($v, $k, ($v == $currenttarget)?'yes':null);
++$targets_cmb->attr('onchange', "jQuery('#mainfrm').submit();");
++
++$main_table->addRow(new CRow(array(
++    'Select Target:',
++    $targets_cmb)));
++
++//Row 2 - Target settings
++$settings_enabled = false;
++switch($currenttarget)
++{
++    case 'ssh':
++    case 'hen':
++        $settings_enabled = true;
++        $tb_name = $currenttarget.'hosts';
++        
++        $hosts = expnodes_gethosts($currenttarget);
++        $hosts_tb = new CTweenBox($exec_frm, $tb_name);
++        foreach($hosts as $h)
++        {
++            if(isset($data[$tb_name])) $selected = 
isset($data[$tb_name][$h['hostid']]);
++            else $selected = true;
++            $hosts_tb->addItem($h['hostid'], $h['host'], $selected);
++        }
++        
++        $settings_elm = $hosts_tb->get('Selected:', 'Excluded:');
++        
++        break;
++    
++    case 'planetlab':
++        $settings_enabled = true;
++        $tb_name = $currenttarget.'hosts';
++        
++        $plhosts = exppl_getSliceNodes();
++        $plhosts_tb = new CTweenBox($exec_frm, $tb_name);
++        foreach($plhosts as $ph)
++        {
++            if(isset($data[$tb_name])) $selected = 
isset($data[$tb_name][$ph['hostid']]);
++            else $selected = true;
++            $plhosts_tb->addItem($ph['hostid'], $ph['hostname'], $selected);
++        }
++        
++        $settings_elm = $plhosts_tb->get('Selected:', 'Excluded:');
++    
++        break;
++    
++    default:
++        $settings_enabled = true;
++        $settings_elm = 'Invalid Target. WHY?';
++        break;
++}
++if($settings_enabled)
++    $main_table->addRow(new CRow(array(
++        'Target Settings:',
++        $settings_elm)));
++
++//Row 3 - Tasklists
++$tasklists = $this->get('tasklists');
++
++$tasklists_tbl = new CTable();
++
++if(isset($data['usetasklist'])) $usetasklist = $data['usetasklist'];
++else $usetasklist = '1';
++$tasklists_rad1 = new CRadioButton('usetasklist', '1', 'input radio', null, 
$usetasklist);
++$tasklists_rad2 = new CRadioButton('usetasklist', '0', 'input radio', null, 
!$usetasklist);
++
++$selectedtasklist = -1;
++if(isset($data['tasklist'])) $selectedtasklist = intval($data['tasklist']);
++$tasklists_cmb = new CComboBox('tasklist');
++foreach($tasklists as $t)
++    $tasklists_cmb->addItem($t['tasklistid'], $t['name'], ($selectedtasklist 
== $t['tasklistid']) ? true : null);
++
++$tasklists_txt = new CTextBox('cmd', isset($data['cmd']) ? $data['cmd'] : '');
++
++$tasklists_tbl->addRow(
++array(
++new CDiv(array(
++$tasklists_rad1, 'Tasklist:')),
++$tasklists_cmb));
++$tasklists_tbl->addRow(
++array(
++new CDiv(array(
++$tasklists_rad2, 'Command:')),
++$tasklists_txt));
++
++$main_table->addRow(new CRow(array(
++    'Select Tasklist / Command:',
++    $tasklists_tbl
++)));
++
++//Row 4 - Monitor experiment
++$mon_tbl = new CTable(null, 'border_dotted');
++$mon_tbl->attr('style', 'padding:5px;');
++
++$monitor_enabled = isset($data['monitor']);
++$mon_chk = new CCheckBox('monitor', $monitor_enabled, 
"javascript:jQuery('#expnamerow').toggle();javascript:jQuery('#exptmplrow').toggle();");
++$mon_tbl->addRow(array(array($mon_chk, ' Enable monitoring')));
++
++$expname_tb = new CTextBox('expname', isset($data['expname']) ? 
$data['expname'] : null );
++$expname_row = new CRow(array(array('Experiment name:', $expname_tb)), null, 
'expnamerow');
++if(!$monitor_enabled)
++    $expname_row->attr('style', 'display:none;');
++$mon_tbl->addRow($expname_row);
++
++$tmplList = new CFormList('tmpllist');
++$tmplList->addRow('Monitor Templates:');
++
++$templates = (isset($data['templates'])) ? $data['templates'] : array();
++$templates = API::Template()->get(array(
++      'templateids' => $templates,
++      'output' => array('templateid', 'name')
++));
++foreach ($templates as $t) {
++      $exec_frm->addVar('templates['.$t['templateid'].']', $t['name']);
++      $tmplList->addRow(array($t['name'], new 
CSubmit('unlink['.$t['templateid'].']', _('Unlink'), null, 'link_menu')));
++}
++
++$tmplAdd = new CMultiSelect(array(
++              'name' => 'templates[]',
++              'objectName' => 'templates',
++              'ignored' => array()
++      ));
++$tmplList->addRow($tmplAdd);
++$tmplList->addRow(new CSubmit('add_template', _('Add'), null, 'link_menu'));
++$tmplRow = new CRow($tmplList, null, 'exptmplrow');
++if(!$monitor_enabled)
++    $tmplRow->attr('style', 'display:none;');
++
++$mon_tbl->addRow($tmplRow);
++
++
++$main_table->addRow(new CRow(array(
++    'Monitor Experiment:',
++    $mon_tbl
++)));
++
++
++$exec_frm->addItem($main_table);
++
++/*
++ * footer
++ */
++$exec_frm->addItem(makeFormFooter(new CSubmit('run', 'Run')));
++
++return $exec_frm;
+diff --git include/views/experiments.files.php 
include/views/experiments.files.php
+new file mode 100644
+index 0000000..1fd1203
+--- /dev/null
++++ include/views/experiments.files.php
+@@ -0,0 +1,30 @@
++<?php
++
++$files = $this->get('files');
++
++$fWidget = new CWidget();
++
++$uploadForm = new CForm('post', null, 'multipart/form-data');
++$uploadForm->addItem(new CInput('file', 'file'));
++$uploadForm->addItem(new CSubmit('upload', 'Upload file'));
++//add maximum size note
++
++$fWidget->addPageHeader('USER FILES', $uploadForm);
++
++$files_tbl = new CTableInfo('No files added yet.');
++$files_tbl->setHeader(array('File name', ''));
++foreach($files as $f)
++{
++    //download link
++    $download_lnk = new CLink($f, '?download='.$f);
++    
++    //delete link
++    $delete_lnk = new CLink('delete', '?delete='.$f);
++    
++    $files_tbl->addRow(array($download_lnk, $delete_lnk));
++    //TODO: add delete, download
++}
++
++$fWidget->addItem($files_tbl);
++
++return $fWidget;
+diff --git include/views/experiments.results.php 
include/views/experiments.results.php
+new file mode 100644
+index 0000000..a8f6b24
+--- /dev/null
++++ include/views/experiments.results.php
+@@ -0,0 +1,72 @@
++<?php
++
++//Main table
++$main_table = new CTableInfo();
++
++$results = $this->get('results');
++$runid = $this->get('runid'); //if set, one of the runs is selected
++
++$main_table->setHeader(array('', 'Status', 'Started On', 'Target', 
'Tasklist/Command', 'Percentage completed', '', ''));
++
++foreach($results as $r)
++{
++    $div_actions = new CDiv();
++    if($r['status'] == 'Running')
++        $div_actions->addItem(new CLink('interrupt', 
'results.php?interrupt='.$r['runid']));
++    else
++    {
++        $div_actions->addItem(new CLink('delete', 
'results.php?delete='.$r['runid']));
++        //$div_actions->addItem(new CButtonDelete('Are you sure you want to 
delete?', $r['runid']));
++        $div_actions->addItem(' | ');
++        $div_actions->addItem(new CLink('re-run', 
'results.php?rerun='.$r['runid']));
++    }
++    
++    //nodes table
++    $nodes_table = new CTableInfo();
++    foreach($r['nodes'] as $n)
++    {
++        $nodes_table->addRow(new CRow(array(
++            $n['interface'],
++            $n['status'],
++            $n['percentage'].'%',
++            new CLink('log', 
'results.php?runid='.$r['runid'].'&hostid='.$n['hostid'])
++        )));
++    }
++    
++    $div_data = new CDiv();
++    $div_data->addItem(new CLink('log', 'results.php?runid='.$r['runid']));
++    if(isset($r['hostgroupid']))
++    {
++        $div_data->addItem(' | ');
++        $div_data->addItem(new CLink('export', 
'results.php?export='.$r['runid']));
++    }
++    
++    $main_row = array(
++        new CButton(null, '+/-', 
"javascript:jQuery('#".$r['runid']."').toggle();"),
++        $r['status'],
++        ($r['startedon'])?$r['startedon']:'',
++        $r['target'],
++        ($r['usetasklist']) ? $r['tasklist'] : $r['command'],
++        $r['percentage'].'%',
++        $div_data,
++        $div_actions
++        );
++    $main_table->addRow(new CRow($main_row));
++    $hidden_col = new CCol($nodes_table, null, count($main_row));
++    $hidden_col->attr('id', $r['runid']);
++    if(empty($runid) || $runid != $r['runid'])
++        $hidden_col->attr('style', 'display:none;');
++    $main_table->addRow(new CRow($hidden_col));
++}
++
++$log = $this->get('log');
++
++if(!empty($log))
++{
++    $res_txt = new CTextArea(null, $log, array('rows' => substr_count($log, 
"\n") + 1, 'readonly' => 1));
++    $res_txt->attr('style', 'width:100%;font-size:15px;');
++    
++    return new CDiv(array($main_table, 'RESULT:', $res_txt));
++}
++else
++    return $main_table;
+diff --git include/views/experiments.targets.php 
include/views/experiments.targets.php
+new file mode 100644
+index 0000000..dc6fec3
+--- /dev/null
++++ include/views/experiments.targets.php
+@@ -0,0 +1,90 @@
++<?php
++$targetlist = $this->get('targetlist');
++$default_target = reset($targetlist);
++$selected_target = $this->get('selected_target');
++if(!$selected_target) $selected_target = $default_target;
++
++//Main form
++$main_frm = new CForm();
++$main_frm->setName('web.experiment.targets.php.');
++$main_frm->attr('id', 'mainfrm');
++
++//Main table
++$main_table = new CTable();
++
++//Row 1 - Targets
++$targets_cmb = new CComboBox('target');
++foreach($targetlist as $k => $v)
++    $targets_cmb->addItem($v, $k, ($v == $selected_target)?'yes':null);
++$targets_cmb->attr('onchange', "jQuery('#mainfrm').submit();");
++$main_table->addRow(array('Target:', $targets_cmb));
++
++//Row 2 - Target edit
++switch($selected_target)
++{
++    case 'ssh': case 'hen':
++        $hosts_lst = new CListBox('hosts[]', null, 12);
++        $hosts = $this->get('hosts');
++        foreach($hosts as $h)
++            $hosts_lst->addItem($h['hostid'], $h['host']);
++        
++        $del_btn = new CButton('delhost', 'Remove', 
"jQuery('select[name=\"hosts[]\"]').find(':selected').remove()");
++        
++        $add_txt = new CTextBox('newhost', null, 30);
++        $add_btn =  new CButton('addhost', 'Add', 
"jQuery('select[name=\"hosts[]\"]').append('<option>'+jQuery('input[name=newhost]').val()+'</option>');jQuery('input[name=newhost]').val('')");
++        
++        $submit_btn = new CSubmit('apply', 'Apply');
++        $submit_btn->attr('onclick', "jQuery('select[name=\"hosts[]\"] 
option').attr('selected', 'yes')");
++        
++        $main_table->addRow(array(strtoupper($selected_target).':', 
array($hosts_lst, $del_btn)));
++        $main_table->addRow(array('', array($add_txt, $add_btn)));
++        $main_table->addRow(array('', $submit_btn));
++        
++        break;
++    
++    case 'planetlab':
++        $pagesize = 20;
++        $pageoffset = intval($this->get('ploffset'));
++        if(!$pageoffset || $pageoffset < 0) $pageoffset = 0;
++        $hostfilter = $this->get('plfilter');
++        if(!$hostfilter) $hostfilter = null;
++        $slicename = exppl_getslicename();
++        $slicenodes = exppl_getSliceNodes();
++        $availnodes = exppl_getAvailableNodes($pageoffset, $pagesize, 
$hostfilter);
++    
++        $pl_tb = new CTweenBox($main_frm, 'plnodes');
++        foreach($slicenodes as $sn)
++            $pl_tb->addItem($sn['node_id'], $sn['hostname'], true);
++        foreach($availnodes as $an)
++            $pl_tb->addItem($an['node_id'], $an['hostname']);
++        
++        $filter_frm = new CForm('get');
++        $filter_frm->attr('id', 'filterfrm');
++        $filter_tb = new CTextBox('plfilter', $hostfilter);
++        $filter_tb->attr('id', 'plfilter');
++        $filter_btn = new CSubmit('filter', 'Filter', 
'jQuery("#ploffset").val(0)');
++        $page_tb = new CTextBox('ploffset', $pageoffset, 2);
++        $page_tb->attr('id', 'ploffset');
++        $prev_btn = new CSubmit('plprev', '<<', 
'jQuery("#ploffset").val(parseInt(jQuery("#ploffset").val(), 10) - 
1);jQuery("#filterfrm").submit();');
++        $next_btn = new CSubmit('plnext', '>>', 
'jQuery("#ploffset").val(parseInt(jQuery("#ploffset").val(), 10) + 
1);jQuery("#filterfrm").submit();');
++        $clear_btn = new CSubmit('plclear', 'Clear', 
'jQuery("#ploffset").val(0);jQuery("#plfilter").val("")');
++        $filter_tbl = new CTable();
++        $filter_tbl->addRow(array(array($prev_btn, $page_tb, $next_btn)));
++        $filter_tbl->addRow(array(array('Filter:', $filter_tb, $filter_btn)));
++        $filter_tbl->addRow(array($clear_btn));
++        $filter_frm->addItem($filter_tbl);
++        
++        $pl_tbl = new CTable();
++        $pl_tbl->addRow(array($pl_tb->get($slicename, 'Available'), 
$filter_frm));
++        
++        $submit_btn = new CSubmit('apply', 'Apply');
++        
++        $main_table->addRow(array('Planetlab', $pl_tbl));
++        $main_table->addRow(array('', $submit_btn));
++        
++        break;
++}
++
++$main_frm->addItem($main_table);
++
++return $main_frm;
+diff --git include/views/experiments.tasklist.edit.php 
include/views/experiments.tasklist.edit.php
+new file mode 100644
+index 0000000..efc5c54
+--- /dev/null
++++ include/views/experiments.tasklist.edit.php
+@@ -0,0 +1,317 @@
++<?php
++
++$new = $this->get('new');
++
++$xml = $this->get('xml');
++if(!$xml)
++    $xml = new SimpleXMLElement('<?xml version="1.0" 
encoding="UTF-8"?><tasklist></tasklist>');
++
++//$targets = $this->get('targets');
++$tid = $this->get('tid');
++if($new)
++    $meta = array();
++else
++    $meta = $this->get('meta');
++$exptasklist_defaults = $this->get('exptasklist_defaults');
++
++function tlview_parseseq($xml, $postfix)
++{
++    $seq_tbl = new CTableInfo('');
++    $seq_tbl->attr('id', "table$postfix");
++    
++    //Top Row:
++    $btns_div = new CDiv();
++    //Delete button
++    $del_btn = new CButton('delete', 'delete', 'javascript: 
jQuery("#row'.$postfix.'").remove()');
++    //Type (hidden)
++    $type_hdn = new CInput('hidden', 'type'.$postfix, 'sequence');
++    $btns_div->addItem($type_hdn);
++    //Add runs
++    $run_cmb = new CComboBox('run');
++    $run_cmb->attr('id', "runs$postfix");
++    $run_cmb->addItem('run', 'run');
++    $run_cmb->addItem('run_per_host', 'run_per_host');
++    $run_cmb->addItem('put', 'put');
++    $run_cmb->addItem('get', 'get');
++    $btns_div->addItem($run_cmb);
++    $js = 'javascript: '; //javascript used to add runs under this sequence
++    $js .= 'if (typeof window.counter'.$postfix.' === "undefined") 
window.counter'.$postfix.' = '.(count($xml->children())+1).';';
++    $js .= 'new_node(jQuery("#runs'.$postfix.'").val(), 
"'.$postfix.'_"+counter'.$postfix.', "table'.$postfix.'", 
counter'.$postfix.'%2);';
++    $js .= 'counter'.$postfix.'++;';
++    $add_btn = new CButton('add', 'Add', $js);
++    $btns_div->addItem($add_btn);
++    //Move up
++    $mvup_btn = new CButton('mvup', 'Move UP', 'javascript: 
p=jQuery("#row'.$postfix.'").prev(); if(p.attr("id")) 
jQuery("#row'.$postfix.'").insertBefore(p);');
++    $btns_div->addItem($mvup_btn);
++    //Move down
++    $mvdown_btn = new CButton('mvdown', 'Move DOWN', 'javascript: 
n=jQuery("#row'.$postfix.'").next(); if(n.attr("id")) 
jQuery("#row'.$postfix.'").insertAfter(n);');
++    $btns_div->addItem($mvdown_btn);
++    
++    $seq_tbl->addRow(array($del_btn, $btns_div));
++    
++    //Sequence attributes
++    
++    //Name attribute
++    $name_tb = new CInput('text', 'name'.$postfix, (string)$xml['name']);
++    $name_tb->addStyle('width: 50em;');
++    $seq_tbl->addRow(array('Name:', $name_tb));
++    
++    //Enabled attribute
++    $enabled_chb = new CCheckBox('enabled'.$postfix, 
(((string)$xml['enabled']) == 'false')?'no':'yes');
++    $seq_tbl->addRow(array('Enabled:', $enabled_chb));
++    
++    
++    $counter = 1;
++    foreach($xml->children() as $c)
++    {
++        $name = trim($c->getName());
++        $row_postfix = $postfix.'_'.$counter;
++        $seq_tbl->addRow(tlview_parserun($name, $c, $row_postfix));
++        $counter++;
++    }
++    
++    //print "<script>var counter$postfix = $counter</script>";
++    
++    return new CRow(array('Sequence:', $seq_tbl), null, "row$postfix");
++}
++function tlview_parserun($type, $xml, $postfix)
++{
++    $run_tbl = new CTableInfo('');
++    
++    //common elements
++    
++    //Top Row:
++    $btns_div = new CDiv();
++    //Delete button
++    $del_btn = new CButton('delete', 'delete', 'javascript: 
jQuery("#row'.$postfix.'").remove()');
++    //Type (hidden)
++    $type_hdn = new CInput('hidden', 'type'.$postfix, $type);
++    $btns_div->addItem($type_hdn);
++    //Move up
++    $mvup_btn = new CButton('mvup', 'Move UP', 'javascript: 
p=jQuery("#row'.$postfix.'").prev(); if(p.attr("id")) 
jQuery("#row'.$postfix.'").insertBefore(p);');
++    $btns_div->addItem($mvup_btn);
++    //Move down
++    $mvdown_btn = new CButton('mvdown', 'Move DOWN', 'javascript: 
n=jQuery("#row'.$postfix.'").next(); if(n.attr("id")) 
jQuery("#row'.$postfix.'").insertAfter(n);');
++    $btns_div->addItem($mvdown_btn);
++    
++    $run_tbl->addRow(array($del_btn, $btns_div));
++    
++    //Name attribute
++    $name_tb = new CInput('text', 'name'.$postfix, (string)$xml['name']);
++    $name_tb->addStyle('width: 50em;');
++    $run_tbl->addRow(array('Name:', $name_tb));
++    
++    //Enabled attribute
++    $enabled_chb = new CCheckBox('enabled'.$postfix, 
(((string)$xml['enabled']) == 'false')?'no':'yes');
++    $run_tbl->addRow(array('Enabled:', $enabled_chb));
++    
++    switch($type)
++    {
++        case 'run':
++            //command
++            $cmd_tb = new CInput('text', 'command'.$postfix, 
(string)$xml->command);
++            $cmd_tb->addStyle('width: 50em;');
++            $run_tbl->addRow(array('Command:', $cmd_tb));
++            
++            //arguments
++            $args_tb = new CInput('text', 'arguments'.$postfix, 
(string)$xml->arguments);
++            $args_tb->addStyle('width: 50em;');
++            $run_tbl->addRow(array('Arguments:', $args_tb));
++            
++            //timeout
++            $timeout_tb = new CInput('text', 'timeout'.$postfix, 
(string)$xml->timeout);
++            $run_tbl->addRow(array('Timeout:', $timeout_tb));
++            
++            //expected_return_code
++            $expected_return_code_tb = new CInput('text', 
'expected$return$code'.$postfix, (string)$xml->expected_return_code);
++            $run_tbl->addRow(array('Expected Return Code:', 
$expected_return_code_tb));
++            
++            //expected_output
++            $expected_output_tb = new CInput('text', 
'expected$output'.$postfix, (string)$xml->expected_output);
++            $expected_output_tb->addStyle('width: 50em;');
++            $run_tbl->addRow(array('Expected Output:', $expected_output_tb));
++            
++            break;
++        case 'run_per_host':
++            //command_file
++            $command_file_tb = new CInput('text', 'command$file'.$postfix, 
(string)$xml->command_file);
++            $command_file_tb->addStyle('width: 50em;');
++            $run_tbl->addRow(array('Command File:', $command_file_tb));
++            
++            //output_prefix
++            $output_prefix_tb = new CInput('text', 'output$prefix'.$postfix, 
(string)$xml->output_prefix);
++            $output_prefix_tb->addStyle('width: 50em;');
++            $run_tbl->addRow(array('Output Prefix:', $output_prefix_tb));
++            
++            //timeout
++            $timeout_tb = new CInput('text', 'timeout'.$postfix, 
(string)$xml->timeout);
++            $run_tbl->addRow(array('Timeout:', $timeout_tb));
++            
++            //expected_return_code
++            $expected_return_code_tb = new CInput('text', 
'expected$return$code'.$postfix, (string)$xml->expected_return_code);
++            $run_tbl->addRow(array('Expected Return Code:', 
$expected_return_code_tb));
++            
++            //expected_output
++            $expected_output_tb = new CInput('text', 
'expected$output'.$postfix, (string)$xml->expected_output);
++            $expected_output_tb->addStyle('width: 50em;');
++            $run_tbl->addRow(array('Expected Output:', $expected_output_tb));
++        
++            break;
++        case 'put':
++            //source
++            $userfiles = expfiles_getuserfiles();
++            $selectedfile = '';
++            if(!empty($xml->source)) $selectedfile = 
basename((string)$xml->source);
++            $source_cmb = new CComboBox('source'.$postfix);
++            foreach($userfiles as $uf)
++                $source_cmb->addItem($uf, $uf, ($selectedfile == 
$uf)?'yes':null);
++            $run_tbl->addRow(array('Source:', $source_cmb));
++            
++            //destination
++            $destination_tb = new CInput('text', 'destination'.$postfix, 
(string)$xml->destination);
++            $destination_tb->addStyle('width: 50em;');
++            $run_tbl->addRow(array('Destination:', $destination_tb));
++        
++            break;
++        case 'get':
++            //source
++            $source_tb = new CInput('text', 'source'.$postfix, 
(string)$xml->source);
++            $source_tb->addStyle('width: 50em;');
++            $run_tbl->addRow(array('Source:', $source_tb));
++            
++            //destination (removed because now all files should go to the 
user specific folder)
++            /*$destination_tb = new CInput('text', 'destination'.$postfix, 
(string)$xml->destination);
++            $destination_tb->addStyle('width: 50em;');
++            $run_tbl->addRow(array('Destination:', $destination_tb));*/
++            break;
++    }
++    
++    //Stop on fail
++    $stop_on_fail_chb = new CCheckBox('stop$on$fail'.$postfix, 
(((string)$xml->stop_on_fail) == 'false')?'no':'yes');
++    $run_tbl->addRow(array('Stop on fail:', $stop_on_fail_chb));
++    
++    return new CRow(array("$type:", $run_tbl), null, "row$postfix");
++    return $run_tbl;
++}
++
++//print_r($xml);
++
++if($new)
++    $main_frm = new CForm('post', 'tasklist.php?new=new');
++else
++    $main_frm = new CForm('post', 'tasklist.php?tid='.$tid);
++$main_tbl = new CTableInfo('');
++$main_tbl->attr('id', 'table_main');
++
++//Top Row:
++$btns_div = new CDiv();
++//'Add run' (all types)
++$run_cmb = new CComboBox('run');
++$run_cmb->attr('id', 'runs_main');
++$run_cmb->addItem('sequence', 'sequence');
++$run_cmb->addItem('run', 'run');
++$run_cmb->addItem('run_per_host', 'run_per_host');
++$run_cmb->addItem('put', 'put');
++$run_cmb->addItem('get', 'get');
++$btns_div->addItem($run_cmb);
++$add_btn = new CButton('add', 'Add', "javascript: 
new_node(jQuery('#runs_main').val(), '_'+counter, 'table_main', counter%2); 
counter++;");
++$btns_div->addItem($add_btn);
++
++$main_tbl->addRow(array('', $btns_div));
++
++//name attribute
++$name_tb = new CInput('text', 'name', (string)$xml['name']);
++$name_tb->addStyle('width: 50em;');
++$main_tbl->addRow(array('Name:', $name_tb));
++
++//description
++$desc_ta = new CTextArea('description', 
(empty($meta['description']))?'':$meta['description']);
++$main_tbl->addRow(array('Description:', $desc_ta));
++
++//shared
++$shared_chb = new CCheckBox('shared', (empty($meta['shared']))?'no':'yes');
++$main_tbl->addRow(array('Shared:', $shared_chb));
++
++//option 1 - Target
++/*$selected_target = 
isset($xml->options->target)?trim((string)$xml->options->target):'remote_ssh';
++$target_cmb = new CComboBox('target');
++foreach($targets as $t)
++    $target_cmb->addItem($t, $t, ($selected_target == $t)?'yes':null);
++$main_tbl->addRow(array('Target:', $target_cmb));*/
++
++//option 2 - Log dir
++$log_dir = 
isset($xml->options->log_dir)?trim((string)$xml->options->log_dir):'';
++$log_dir_tb = new CInput('text', 'log$dir', $log_dir);
++$log_dir_tb->addStyle('width: 50em;');
++$main_tbl->addRow(array('Log Dir:', $log_dir_tb));
++
++$counter = 1;
++foreach($xml->children() as $c)
++{
++    $name = trim($c->getName());
++    if($name == 'sequence')
++    {
++        $main_tbl->addRow(tlview_parseseq($c, '_'.$counter));
++        $counter++;
++    }
++    elseif($name == 'run' || $name == 'run_per_host' || $name == 'put' || 
$name == 'get')
++    {
++        $main_tbl->addRow(tlview_parserun($name, $c, '_'.$counter));
++        $counter++;
++    }
++}
++
++$main_frm->addItem($main_tbl);
++
++//$main_frm->addItem(new CInput('hidden', 'tid', $tid));
++if($new)
++    $main_frm->addItem(new CSubmit('add', 'Add'));
++else
++    $main_frm->addItem(new CSubmit('update', 'Update'));
++
++/*print "TESTING:<br/>";
++$tmp = tlview_parserun('run', $default_run, '_100');
++print $tmp->toString();
++print "END TESTING";*/
++
++
++?>
++
++<script>
++var counter = <?=$counter?>;
++
++function new_node(type, postfix, table_id, parity)
++{
++var html = '';
++switch(type)
++{
++case 'sequence':
++html = '<?php print tlview_parseseq($exptasklist_defaults["sequence"], 
"%placeholder%"); ?>';
++break;
++case 'run':
++html = '<?php print tlview_parserun("run", $exptasklist_defaults["run"], 
"%placeholder%"); ?>';
++break;
++case 'run_per_host':
++html = '<?php print tlview_parserun("run_per_host", 
$exptasklist_defaults["run_per_host"], "%placeholder%"); ?>';
++break;
++case 'put':
++html = '<?php print tlview_parserun("put", $exptasklist_defaults["put"], 
"%placeholder%"); ?>';
++break;
++case 'get':
++html = '<?php print tlview_parserun("get", $exptasklist_defaults["get"], 
"%placeholder%"); ?>';
++break;
++}
++
++html = html.replace(/%placeholder%/g, postfix);
++jQuery('#'+table_id).append(html);
++var cl = (parity == 0)?'even_row':'odd_row';
++jQuery('#row'+postfix).addClass(cl);
++jQuery('#row'+postfix).attr('origclass', cl);
++jQuery('#name'+postfix).focus();
++}
++
++</script>
++
++<?php
++
++return $main_frm;
+diff --git include/views/experiments.tasklist.php 
include/views/experiments.tasklist.php
+new file mode 100644
+index 0000000..02babc4
+--- /dev/null
++++ include/views/experiments.tasklist.php
+@@ -0,0 +1,50 @@
++<?php
++
++$tasklists = $this->get('tasklists');
++
++$tlWidget = new CWidget();
++
++$headerDiv = new CDiv();
++
++$createForm = new CForm('get');
++$createForm->addItem(new CSubmit('sync', 'Sync with GPLMT directory'));
++$createForm->addItem(new CSubmit('new', 'Create tasklist'));
++$headerDiv->addItem($createForm);
++
++$importForm = new CForm('post', null, 'multipart/form-data');
++$importForm->addItem(new CFile('import_file'));
++$importForm->addItem(new CSubmit('import', 'Import XML file'));
++$headerDiv->addItem($importForm);
++
++$tlWidget->addPageHeader('CONFIGURATION OF TASKLISTS', $headerDiv);
++
++//main form
++$tlForm = new CForm('get');
++$tlForm->setName('tasklistForm');
++
++//main table
++$tlTable = new CTableInfo('No tasklists defined.');
++$tlTable->setHeader(array('Name', 'Description', 'User', 'Shared', ''));
++
++foreach($tasklists as $tl)
++{
++    //Name link
++    $name_lnk = new CLink($tl['name'], '?tid='.$tl['tasklistid']);
++    
++    //Delete link
++    $del_btn = new CButtonDelete('Are you sure you want to delete this 
tasklist?', $tl['tasklistid']);
++    
++    $tlTable->addRow(array(
++        $name_lnk,
++        ($tl['description'])?$tl['description']:'',
++        $tl['username'],
++        ($tl['shared'])?'Yes':'No',
++        $del_btn
++        ));
++}
++
++$tlForm->addItem($tlTable);
++
++$tlWidget->addItem($tlForm);
++
++return $tlWidget;
+diff --git include/views/general.script.execute-parallel.php 
include/views/general.script.execute-parallel.php
+new file mode 100644
+index 0000000..4bc5aca
+--- /dev/null
++++ include/views/general.script.execute-parallel.php
+@@ -0,0 +1,54 @@
++<?php
++/*
++** Zabbix
++** Copyright (C) 2000-2011 Zabbix SIA
++**
++** This program is free software; you can redistribute it and/or modify
++** it under the terms of the GNU General Public License as published by
++** the Free Software Foundation; either version 2 of the License, or
++** (at your option) any later version.
++**
++** This program is distributed in the hope that it will be useful,
++** but WITHOUT ANY WARRANTY; without even the implied warranty of
++** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++** GNU General Public License for more details.
++**
++** You should have received a copy of the GNU General Public License
++** along with this program; if not, write to the Free Software
++** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
USA.
++**/
++
++
++//javascript item
++$js = new CJSscript();
++
++$numHosts = count($this->data['hosts']);
++
++$js->addItem("<div id=\"counter\" 
style=\"font-size:20px;padding:5px;\">0/$numHosts</div>");
++$js->addItem("<div id=\"content\"></div>");
++$js->addItem("<script type=\"text/javascript\" 
src=\"js/jquery/jquery.js\"></script>");
++$js->addItem("<script type=\"text/javascript\">");
++$js->addItem("var hosts = new Array();");
++$js->addItem("var ctr = 0;");
++
++for($i = 0; $i < $numHosts; $i++)
++{
++    $host = $this->data['hosts'][$i];
++    $js->addItem("hosts[$i] = ".$host['hostid'].";");
++}
++
++$sid = $this->data['sid'];
++$scriptid = $this->data['scriptid'];
++$js->addItem("for(var i=0;i<$numHosts;i++){
++    $.ajax({
++    url: 
\"scripts_exec.php?sid=$sid&execute=1&scriptid=$scriptid&strip=1&hostid=\"+hosts[i],
++    async: true,
++    success: function(data) { $('#content').append(data); ctr++; 
$('#counter').html(ctr+'/$numHosts') }
++    });
++}");
++
++
++//$js->addItem();
++$js->addItem("</script>");
++
++return $js;
+diff --git js/main.js js/main.js
+index ab5c4c0..6ead31b 100644
+--- js/main.js
++++ js/main.js
+@@ -103,7 +103,7 @@ var PageRefresh = {
+  * Main menu
+  */
+ var MMenu = {
+-      menus:                  {'empty': 0, 'view': 0, 'cm': 0, 'reports': 0, 
'config': 0, 'admin': 0},
++      menus:                  {'empty': 0, 'view': 0, 'cm': 0, 'reports': 0, 
'config': 0, 'admin': 0, 'experiment':0},
+       def_label:              null,
+       sub_active:     false,
+       timeout_reset:  null,
+diff --git manage_monitoring.php manage_monitoring.php
+new file mode 100644
+index 0000000..a01bbfa
+--- /dev/null
++++ manage_monitoring.php
+@@ -0,0 +1,61 @@
++<?php
++/*
++** Zabbix
++** Copyright (C) 2000-2011 Zabbix SIA
++**
++** This program is free software; you can redistribute it and/or modify
++** it under the terms of the GNU General Public License as published by
++** the Free Software Foundation; either version 2 of the License, or
++** (at your option) any later version.
++**
++** This program is distributed in the hope that it will be useful,
++** but WITHOUT ANY WARRANTY; without even the implied warranty of
++** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++** GNU General Public License for more details.
++**
++** You should have received a copy of the GNU General Public License
++** along with this program; if not, write to the Free Software
++** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
USA.
++**/
++
++require_once 'include/config.inc.php';
++require_once 'include/hosts.inc.php';
++require_once 'include/items.inc.php';
++require_once 'include/forms.inc.php';
++
++$page['title'] = _('Manage Monitoring');
++$page['file'] = 'manage_monitoring.php';
++
++define('ZBX_PAGE_NO_MENU', 1);
++
++// VAR        TYPE    OPTIONAL        FLAGS   VALIDATION      EXCEPTION
++$fields = array(
++      'template'      =>      array(T_ZBX_INT,        O_OPT,  P_SYS,          
DB_ID,  true),
++      'action'                =>      array(T_ZBX_STR,        O_OPT,  
NOT_EMPTY,      null,   true),
++);
++check_fields($fields);
++
++$templates = array_keys($_REQUEST['template']);
++
++//fetch template
++$options = array(
++      'templateids' => $templates,
++      'selectItems' => array(),
++      'output' => array('name')
++);
++$templates = API::Template()->get($options);
++
++//pull all item ids in array
++$all_items = array();
++foreach($templates as $temp)
++{
++      foreach($temp['items'] as $item)
++              $all_items[] = $item['itemid'];
++}
++
++//perform action
++DBstart();
++$go_result = ($_REQUEST['action'] == 
'disable')?disable_item($all_items):activate_item($all_items);
++$go_result = DBend($go_result);
++
++jsRedirect('dashboard.php');
+diff --git results.php results.php
+new file mode 100644
+index 0000000..5a01c7a
+--- /dev/null
++++ results.php
+@@ -0,0 +1,122 @@
++<?php
++
++require_once dirname(__FILE__).'/include/config.inc.php';
++require_once dirname(__FILE__).'/include/experiments/inc.php';
++
++$page['title'] = _('Experiment Results');
++$page['file'] = 'results.php';
++$page['hist_arg'] = array('resid');
++
++if(isset($_REQUEST['export']))
++{
++    if(exprun_checkpermission($_REQUEST['export']))
++    {
++        $monitor = exprun_getmonitorrecord($_REQUEST['export']);
++        if($monitor)
++        {
++            header("Content-type: text/csv");
++            header("Content-Disposition: attachment; filename=export.csv");
++            header("Pragma: no-cache");
++            header("Expires: 0");
++            exp_getmonitorhistory($monitor['hostgroupid']);
++            exit;
++        }
++        else
++            error("Monitoring was not enabled for this run.");
++    }
++    else
++        error("No permission to export.");
++}
++
++require_once dirname(__FILE__).'/include/page_header.php';
++
++// VAR        TYPE    OPTIONAL        FLAGS   VALIDATION      EXCEPTION
++$fields = array(
++    'runid' =>   array(T_ZBX_INT, O_OPT, P_SYS|P_ACT, null, null),
++    'hostid' =>   array(T_ZBX_INT, O_OPT, P_SYS|P_ACT, null, null),
++    'delete' =>    array(T_ZBX_INT, O_OPT, P_SYS|P_ACT, null, null),
++    'interrupt' =>    array(T_ZBX_INT, O_OPT, P_SYS|P_ACT, null, null),
++    'rerun' =>    array(T_ZBX_INT, O_OPT, P_SYS|P_ACT, null, null)
++);
++check_fields($fields);
++
++/*
++ * Actions
++ */
++
++if(isset($_REQUEST['delete']))
++{
++    if(exprun_checkpermission($_REQUEST['delete']))
++    {
++        exprun_delete($_REQUEST['delete']);    
++        jsRedirect('results.php');
++    }
++    else
++        error("No permission to delete.");
++}
++
++if(isset($_REQUEST['interrupt']))
++{
++    if(exprun_checkpermission($_REQUEST['interrupt']))
++    {
++        exprun_interrupt($_REQUEST['interrupt']);
++        jsRedirect('results.php');
++    }
++    else
++        error("No permission to interrupt.");
++}
++
++if(isset($_REQUEST['rerun']))
++{
++    if(exprun_checkpermission($_REQUEST['rerun']))
++    {
++        exprun_rerun($_REQUEST['rerun']);
++        jsRedirect('results.php');
++    }
++    else
++        error("No permission to rerun.");
++}
++
++/*
++ * Display
++ */
++$resView = new CView('experiments.results');
++
++$results = exprun_getall(true);
++$resView->set('results', $results);
++
++if(isset($_REQUEST['runid']))
++{
++    if(exprun_verifyid($_REQUEST['runid']))
++    {
++        foreach($results as $r) //get the specific run that we want to 
display the log for
++        {
++            if($r['runid'] == $_REQUEST['runid'])
++            {
++                $run = $r;
++                break;
++            }
++        }
++        
++        $sep = 
"\n=================================================================\n";
++        $log = '';
++        foreach($run['nodes'] as $n)
++        {
++            if(isset($_REQUEST['hostid']) && $n['hostid'] == 
$_REQUEST['hostid']) //print the log of only a specific host
++            {
++                $log = $n['log'];
++                break;
++            }
++            else
++                $log .= $n['log'].$sep;
++        }
++        
++        $resView->set('log', $log);
++        $resView->set('runid', $run['runid']);
++    }
++}
++
++$resView->render();
++$resView->show();
++
++require_once dirname(__FILE__).'/include/page_footer.php';
+diff --git targets.php targets.php
+new file mode 100644
+index 0000000..3dc0d24
+--- /dev/null
++++ targets.php
+@@ -0,0 +1,53 @@
++<?php
++
++error_reporting(E_ALL & ~E_DEPRECATED & ~E_STRICT);
++
++require_once dirname(__FILE__).'/include/config.inc.php';
++require_once dirname(__FILE__).'/include/experiments/inc.php';
++
++$page['title'] = _('Target Configuration');
++$page['file'] = 'targets.php';
++$page['hist_arg'] = array('targetid');
++
++require_once dirname(__FILE__).'/include/page_header.php';
++
++/*
++ * Actions
++ */
++//print_r($_REQUEST);
++
++if(isset($_REQUEST['target']) && isset($_REQUEST['apply']))
++{
++    switch($_REQUEST['target'])
++    {
++        case 'ssh':
++        case 'hen':
++            $hosts = (isset($_REQUEST['hosts'])) ? $_REQUEST['hosts'] : 
array();
++            exptarget_updatehosts($hosts, $_REQUEST['target']);
++            break;
++        
++        case 'planetlab':
++            if(isset($_REQUEST['plnodes']) && is_array($_REQUEST['plnodes']))
++                exppl_updateSliceNodes($_REQUEST['plnodes']);
++            break;
++    }
++}
++
++/*
++ * Display
++ */
++$targetsView = new CView('experiments.targets');
++
++$targetsView->set('targetlist', $exp_targetlist);
++$selected_target = (isset($_REQUEST['target'])) ? $_REQUEST['target'] : 
reset($exp_targetlist);
++$targetsView->set('selected_target', $selected_target);
++
++$targetsView->set('hosts', expnodes_gethosts($selected_target));
++
++if(isset($_REQUEST['ploffset'])) $targetsView->set('ploffset', 
$_REQUEST['ploffset']);
++if(isset($_REQUEST['plfilter']) && trim($_REQUEST['plfilter']) != '') 
$targetsView->set('plfilter', $_REQUEST['plfilter']);
++
++$targetsView->render();
++$targetsView->show();
++
++require_once dirname(__FILE__).'/include/page_footer.php';
+diff --git tasklist.php tasklist.php
+new file mode 100644
+index 0000000..fbaeeed
+--- /dev/null
++++ tasklist.php
+@@ -0,0 +1,138 @@
++<?php
++
++require_once dirname(__FILE__).'/include/config.inc.php';
++require_once dirname(__FILE__).'/include/experiments/inc.php';
++
++$page['title'] = _('Tasklists');
++$page['file'] = 'tasklist.php';
++$page['hist_arg'] = array('taskid');
++
++require_once dirname(__FILE__).'/include/page_header.php';
++
++// VAR        TYPE    OPTIONAL        FLAGS   VALIDATION      EXCEPTION
++/*$fields = array(
++      'tid' =>                array(T_ZBX_INT, O_OPT, P_SYS, null, null),
++);
++check_fields($fields);*/
++
++
++/*
++ * Actions
++ */
++if(isset($_REQUEST['tid']) && isset($_REQUEST['update']))
++{
++    $tid = intval($_REQUEST['tid']);
++    if(exptasklist_allowed($tid) == 2) //check user permission (read/write)
++        exptasklist_update($tid, $_REQUEST);
++    else
++        error("Permission denied!");
++}
++else if(isset($_REQUEST['add']))
++{
++    if(exptasklist_add($_REQUEST))
++        jsRedirect('tasklist.php');
++}
++else if(isset($_REQUEST['delete']))
++{
++    $tid = intval(substr($_REQUEST['delete'], 1));
++    
++    if(exptasklist_allowed($tid) == 2)
++    {
++        if(exptasklist_delete($tid))
++            jsRedirect('tasklist.php');
++    }
++    else
++        error("Permission denied!");
++}
++else if (isset($_REQUEST['sync']))
++{
++    $c = exptasklist_addall();
++    info("$c new tasklists added.");
++}
++else if(isset($_FILES['import_file']))
++{
++  try
++  {
++    $file = new CUploadFile($_FILES['import_file']);
++    
++    $reader = new CXmlImportReader();
++    $filecontent = $file->getContent();
++    $reader->read($filecontent);
++    
++    $tlView = new CView('experiments.tasklist.edit');
++    $tlView->set('xml', simplexml_load_string($filecontent));
++    $tlView->set('exptasklist_defaults', $exptasklist_defaults);
++    $tlView->set('userfiles', expfiles_getuserfiles());
++    $tlView->set('new', true);
++    
++    $tlView->render();
++    $tlView->show();
++    
++    require_once dirname(__FILE__).'/include/page_footer.php';
++    
++    exit();
++  }
++  catch (Exception $e)
++  {
++              error($e->getMessage());
++              show_messages(false, null, _('Import failed'));
++      }
++}
++
++
++/*
++ * Display
++ */
++if(isset($_REQUEST['tid']))
++{
++    $tid = intval($_REQUEST['tid']);
++    if(exptasklist_allowed($tid) > 0) //check user permission (read or 
read/write)
++    {
++        //Get tasklist metadata
++        $meta = exptasklist_getbyid($tid);
++        //Get tasklist XML content
++        $xml = exptasklist_getcontent($tid);
++        if($xml)
++        {
++            $tlView = new CView('experiments.tasklist.edit');
++
++            $tlView->set('tid', $tid);
++            $tlView->set('xml', simplexml_load_string($xml));
++            //$tlView->set('targets', exp_gettargets());
++            $tlView->set('meta', $meta);
++            $tlView->set('exptasklist_defaults', $exptasklist_defaults);
++            $tlView->set('userfiles', expfiles_getuserfiles());
++
++            $tlView->render();
++            $tlView->show();
++
++        }
++        else
++            error("Error while loading tasklist!");
++    }
++    else
++        error("Permission denied!");
++}
++elseif(isset($_REQUEST['new']))
++{
++    $tlView = new CView('experiments.tasklist.edit');
++    
++    $tlView->set('new', true);
++    //$tlView->set('targets', exp_gettargets());
++    $tlView->set('exptasklist_defaults', $exptasklist_defaults);
++    $tlView->set('userfiles', expfiles_getuserfiles());
++    
++    $tlView->render();
++    $tlView->show();
++}
++else
++{
++    $tlView = new CView('experiments.tasklist');
++    
++    $tlView->set('tasklists', exptasklist_getall(true));
++    
++    $tlView->render();
++    $tlView->show();
++}
++
++require_once dirname(__FILE__).'/include/page_footer.php';

Added: eclectic/gplmt-ui/Zabbix-2.2/schema.sql
===================================================================
--- eclectic/gplmt-ui/Zabbix-2.2/schema.sql                             (rev 0)
+++ eclectic/gplmt-ui/Zabbix-2.2/schema.sql     2014-05-26 19:45:47 UTC (rev 
33405)
@@ -0,0 +1,128 @@
+SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
+SET time_zone = "+00:00";
+
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
+/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
+/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
+/*!40101 SET NAMES utf8 */;
+
+
+DROP TABLE IF EXISTS `exp_config`;
+CREATE TABLE IF NOT EXISTS `exp_config` (
+  `configid` int(11) NOT NULL AUTO_INCREMENT,
+  `section` varchar(100) COLLATE utf8_bin NOT NULL,
+  `name` varchar(200) COLLATE utf8_bin NOT NULL,
+  `label` varchar(100) COLLATE utf8_bin NOT NULL,
+  `description` text COLLATE utf8_bin,
+  `type` varchar(100) COLLATE utf8_bin NOT NULL,
+  `default_value` varchar(500) COLLATE utf8_bin NOT NULL,
+  `user_editable` tinyint(1) NOT NULL,
+  PRIMARY KEY (`configid`)
+) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=31 ;
+
+DROP TABLE IF EXISTS `exp_configenum`;
+CREATE TABLE IF NOT EXISTS `exp_configenum` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `configid` int(11) NOT NULL,
+  `label` text COLLATE utf8_bin NOT NULL,
+  `value` text COLLATE utf8_bin NOT NULL,
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=3 ;
+
+DROP TABLE IF EXISTS `exp_host`;
+CREATE TABLE IF NOT EXISTS `exp_host` (
+  `hostid` int(11) NOT NULL AUTO_INCREMENT,
+  `target` varchar(200) COLLATE utf8_bin NOT NULL,
+  `userid` int(11) NOT NULL,
+  `host` text COLLATE utf8_bin NOT NULL,
+  `pl_nodeid` int(11) DEFAULT NULL,
+  PRIMARY KEY (`hostid`,`target`)
+) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=1637 ;
+
+DROP TABLE IF EXISTS `exp_monitor`;
+CREATE TABLE IF NOT EXISTS `exp_monitor` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `runid` int(11) NOT NULL,
+  `userid` int(11) NOT NULL,
+  `hostgroupid` int(11) NOT NULL,
+  `usergroupid` int(11) NOT NULL,
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=43 ;
+
+DROP TABLE IF EXISTS `exp_run`;
+CREATE TABLE IF NOT EXISTS `exp_run` (
+  `runid` int(11) NOT NULL AUTO_INCREMENT,
+  `startedon` timestamp NULL DEFAULT NULL,
+  `usetasklist` tinyint(1) NOT NULL DEFAULT '1',
+  `tasklistid` int(11) DEFAULT NULL,
+  `command` varchar(200) COLLATE utf8_bin DEFAULT NULL,
+  `target` varchar(200) COLLATE utf8_bin NOT NULL,
+  `pid` int(11) DEFAULT NULL,
+  `userid` int(11) NOT NULL,
+  `status` int(11) NOT NULL DEFAULT '0',
+  `percentage` double NOT NULL DEFAULT '0',
+  `fullcommand` text COLLATE utf8_bin,
+  PRIMARY KEY (`runid`)
+) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=146 ;
+
+DROP TABLE IF EXISTS `exp_runnode`;
+CREATE TABLE IF NOT EXISTS `exp_runnode` (
+  `runid` int(11) NOT NULL,
+  `hostid` int(11) NOT NULL,
+  `target` varchar(200) COLLATE utf8_bin NOT NULL,
+  `status` int(11) NOT NULL DEFAULT '0',
+  `percentage` double NOT NULL DEFAULT '0',
+  `log` mediumtext COLLATE utf8_bin NOT NULL,
+  PRIMARY KEY (`runid`,`hostid`,`target`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+
+DROP TABLE IF EXISTS `exp_tasklist`;
+CREATE TABLE IF NOT EXISTS `exp_tasklist` (
+  `tasklistid` int(11) NOT NULL AUTO_INCREMENT,
+  `name` varchar(100) COLLATE utf8_bin NOT NULL,
+  `description` text COLLATE utf8_bin,
+  `fsname` varchar(100) COLLATE utf8_bin NOT NULL,
+  `userid` int(11) NOT NULL,
+  `shared` tinyint(1) NOT NULL,
+  PRIMARY KEY (`tasklistid`)
+) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=27 ;
+
+DROP TABLE IF EXISTS `exp_userconfig`;
+CREATE TABLE IF NOT EXISTS `exp_userconfig` (
+  `configid` int(11) NOT NULL,
+  `userid` int(11) NOT NULL,
+  `value` varchar(500) COLLATE utf8_bin NOT NULL,
+  `enabled` tinyint(1) NOT NULL,
+  PRIMARY KEY (`configid`,`userid`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+
+DROP TRIGGER IF EXISTS tr_gplmtdelay;
+
+delimiter |
+CREATE TRIGGER tr_gplmtdelay BEFORE UPDATE ON hosts
+FOR EACH ROW
+BEGIN
+    IF OLD.available = 0 AND NEW.available = 1 THEN
+        SET @dummy = GET_LOCK('lck_gplmtdelay', 10);
+
+        SELECT exp_run.runid, exp_run.status, exp_run.fullcommand
+        FROM hosts_groups, exp_monitor, exp_run
+        WHERE hosts_groups.hostid = NEW.hostid
+        AND hosts_groups.groupid = exp_monitor.hostgroupid
+        AND exp_monitor.runid = exp_run.runid
+        LIMIT 1
+        INTO @run_id, @gplmt_status, @command;
+
+        IF @gplmt_status = 3 THEN
+            SET @pid = sys_eval(@command);
+            UPDATE exp_run SET pid = @pid, status = 1, startedon = 
CURRENT_TIMESTAMP WHERE runid = @run_id;
+        END IF;
+
+        SET @dummy = RELEASE_LOCK('lck_gplmtdelay');
+    END IF;
+END;|
+delimiter ;
+
+/*!40101 SET address@hidden */;
+/*!40101 SET address@hidden */;
+/*!40101 SET address@hidden */;

Deleted: eclectic/gplmt-ui/data.sql
===================================================================
--- eclectic/gplmt-ui/data.sql  2014-05-26 19:38:06 UTC (rev 33404)
+++ eclectic/gplmt-ui/data.sql  2014-05-26 19:45:47 UTC (rev 33405)
@@ -1,54 +0,0 @@
--- phpMyAdmin SQL Dump
--- version 3.4.11.1deb2
--- http://www.phpmyadmin.net
---
--- Host: localhost
--- Generation Time: Sep 26, 2013 at 04:40 PM
--- Server version: 5.5.31
--- PHP Version: 5.4.4-14+deb7u4
-
-SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
-SET time_zone = "+00:00";
-
-
-/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
-/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
-/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
-/*!40101 SET NAMES utf8 */;
-
---
--- Database: `zabbix`
---
-
---
--- Dumping data for table `exp_config`
---
-
-INSERT INTO `exp_config` (`configid`, `section`, `name`, `label`, 
`description`, `type`, `default_value`, `user_editable`) VALUES
-(1, 'ssh', 'ssh_username', 'SSH username', 'Username for SSH access', 'text', 
'', 1),
-(2, 'ssh', 'ssh_password', 'SSH password', 'Password for SSH access or 
password for the SSH keyfile', 'password', '', 1),
-(3, 'ssh', 'ssh_keyfile', 'SSH keyfile', 'SSH key for login', 'file', '', 1),
-(16, 'gplmt', 'notification', 'Notification', 'Which notification mechanism to 
use: simple, result', 'text', 'result', 0),
-(17, 'gplmt', 'max_parallelism', 'Max Parallelism', 'Number of parallel 
workers, use 0 for unlimited', 'integer', '10', 0),
-(18, 'planetlab', 'slice', 'Planetlab Slice', 'Name of your PlanetLab Slice', 
'text', '', 1),
-(20, 'planetlab', 'api_url', 'PLC/PLE', 'Use PlanetLab Central or PlanetLab 
Europe', 'enum', 'https://www.planet-lab.eu/PLCAPI/', 1),
-(21, 'planetlab', 'username', 'PlanetLab API username', 'Your login to the 
planetlab website\r\nto access the planetlab API', 'text', '', 1),
-(22, 'planetlab', 'password', 'PlanetLab API password', 'Your password for the 
planetlab\r\nwebsite to access the planetlab API', 'password', '', 1),
-(25, 'ssh', 'ssh_transfer', 'SSH Transfer', 'Protocol for put get operations: 
scp, sftp', 'text', 'scp', 0),
-(26, 'ssh', 'ssh_use_known_hosts', 'SSH: Use Known Hosts', 'Use system''s SSH 
"known hosts" file', 'boolean', 'yes', 0),
-(27, 'ssh', 'add_unkown_hostkeys', 'SSH: Add Unknown Hostkeys', 'Add node 
hostkeys automatically', 'boolean', 'yes', 0),
-(28, 'gplmt', 'userdir', 'User Directory', 'User specific directory for 
put/get operations', 'text', '', 0);
-
-INSERT INTO `zabbix`.`exp_config` (`configid`, `section`, `name`, `label`, 
`description`, `type`, `default_value`, `user_editable`) VALUES (NULL, 
'planetlab', 'pl_keyfile', 'Planetlab keyfile', 'Private key file for 
connecting to planetlab nodes', 'file', '', '1'), (NULL, 'planetlab', 
'pl_keyfile_password', 'Planetlab keyfile password', 'Password used to unlock 
private key file (if needed)', 'password', '', '1');
-
---
--- Dumping data for table `exp_configenum`
---
-
-INSERT INTO `exp_configenum` (`id`, `configid`, `label`, `value`) VALUES
-(1, 20, 'Planetlab Central', 'https://www.planet-lab.org/PLCAPI/'),
-(2, 20, 'Planetlab Europe', 'https://www.planet-lab.eu/PLCAPI/');
-
-/*!40101 SET address@hidden */;
-/*!40101 SET address@hidden */;
-/*!40101 SET address@hidden */;

Deleted: eclectic/gplmt-ui/diff
===================================================================
--- eclectic/gplmt-ui/diff      2014-05-26 19:38:06 UTC (rev 33404)
+++ eclectic/gplmt-ui/diff      2014-05-26 19:45:47 UTC (rev 33405)
@@ -1,3058 +0,0 @@
-diff --git conf.php conf.php
-new file mode 100644
-index 0000000..c88d8a6
---- /dev/null
-+++ conf.php
-@@ -0,0 +1,31 @@
-+<?php
-+
-+require_once dirname(__FILE__).'/include/config.inc.php';
-+require_once dirname(__FILE__).'/include/experiments/inc.php';
-+
-+$page['title'] = _('User Configuration');
-+$page['file'] = 'conf.php';
-+$page['hist_arg'] = array('confid');
-+
-+require_once dirname(__FILE__).'/include/page_header.php';
-+
-+/*
-+ * Actions
-+ */
-+if(isset($_REQUEST['update']))
-+{
-+    //print_r($_REQUEST);
-+    expconfig_update($_REQUEST);
-+}
-+
-+/*
-+ * Display
-+ */
-+$filesView = new CView('experiments.conf');
-+
-+$filesView->set('conf', expconfig_getuserconfig());
-+
-+$filesView->render();
-+$filesView->show();
-+
-+require_once dirname(__FILE__).'/include/page_footer.php';
-diff --git conf/.gitignore conf/.gitignore
-new file mode 100644
-index 0000000..d6cdf1c
---- /dev/null
-+++ conf/.gitignore
-@@ -0,0 +1 @@
-+zabbix.conf.php
-diff --git dashboard.php dashboard.php
-index fe17a67..e71abb8 100644
---- dashboard.php
-+++ dashboard.php
-@@ -253,6 +253,11 @@ insert_js('var page_menu='.zbx_jsvalue($menu).";\n".'var 
page_submenu='.zbx_jsva
-  */
- $leftColumn = array();
- 
-+// Manage monitoring
-+$manage_wdgt = new CUIWidget('hat_managemonitoring', 
make_manage_monitoring(), 1);
-+$manage_wdgt->setHeader(_('Manage Monitoring'));
-+$leftColumn[] = $manage_wdgt;
-+
- // favorite graphs
- $graph_menu = get_icon('menu', array('menu' => 'graphs'));
- $fav_grph = new CUIWidget('hat_favgrph', make_favorite_graphs(), 
CProfile::get('web.dashboard.hats.hat_favgrph.state', 1));
-@@ -297,6 +302,12 @@ if ($USER_DETAILS['type'] == USER_TYPE_SUPER_ADMIN) {
-       $rightColumn[] = $zbxStatus;
- }
- 
-+// run scripts
-+$scripts_wdgt = new CUIWidget('hat_runscripts', make_run_scripts(), 1);
-+$scripts_wdgt->setHeader(_('Run Scripts'));
-+//$scripts_wdgt->setFooter(new CLink(_('Graphs').' &raquo;', 'charts.php', 
'highlight'), true);
-+$rightColumn[] = $scripts_wdgt;
-+
- // system status
- $refresh_menu = new CIcon(_('Menu'), 'iconmenu', 
'create_page_menu(event,"hat_syssum");');
- $sys_stat = new CUIWidget('hat_syssum', new CSpan(_('Loading...'), 
'textcolorstyles'), CProfile::get('web.dashboard.hats.hat_syssum.state', 1));
-diff --git execute.php execute.php
-new file mode 100644
-index 0000000..0428d3e
---- /dev/null
-+++ execute.php
-@@ -0,0 +1,69 @@
-+<?php
-+
-+require_once dirname(__FILE__).'/include/config.inc.php';
-+require_once dirname(__FILE__).'/include/experiments/inc.php';
-+
-+$page['title'] = _('Deploy & Execute');
-+$page['file'] = 'execute.php';
-+$page['hist_arg'] = array('execid');
-+
-+require_once dirname(__FILE__).'/include/page_header.php';
-+
-+// VAR        TYPE    OPTIONAL        FLAGS   VALIDATION      EXCEPTION
-+/*$fields = array(
-+      'run' =>                array(T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, 
null),
-+      'nodes' =>              array(T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, 
'isset({run})'),
-+      'usetasklist' =>   array(T_ZBX_INT, O_OPT, P_SYS|P_ACT, IN('0,1'), 
'isset({run})'),
-+      'tasklist' =>   array(T_ZBX_INT, O_OPT, P_SYS|P_ACT, null, 
'isset({run})'),
-+      'cmd' =>   array(T_ZBX_STR, O_OPT, P_SYS|P_ACT, null, 'isset({run})'),
-+      'sync' =>   array(T_ZBX_INT, O_OPT, null, null, null)
-+);
-+check_fields($fields);*/
-+
-+
-+/*
-+ * Actions
-+ */
-+
-+if(isset($_REQUEST['run']))
-+{
-+    $usetasklist = intval($_REQUEST['usetasklist']);
-+    $tasklist = intval($_REQUEST['tasklist']);
-+
-+    $cmd = trim($_REQUEST['cmd']);
-+    $cmd_empty = empty($cmd);
-+    
-+    if($usetasklist == 0 && $cmd_empty)
-+        error("Please specify the command to run.");
-+    elseif(!isset($_REQUEST['target']))
-+        error("Please specify target.");
-+    elseif(!isset($_REQUEST['hosts']) || count($_REQUEST['hosts']) == 0)
-+        error("Please specify hosts to run");
-+    else
-+    {
-+        $res = exprun_new($_REQUEST['target'], $_REQUEST['hosts'], 
$usetasklist, $tasklist, $cmd);
-+        if($res == EXP_ERR_GPLMT_DIR)
-+            error("Could not verify GPLMT files, please make sure that they 
exist and write permissions are enabled.");
-+        elseif($res == EXP_ERR_PERMISSION)
-+            error("Permission error.");
-+        elseif($res == EXP_ERR_INVALID_TARGET)
-+            error("Invalid target!");
-+        else
-+            jsRedirect('results.php');
-+    }
-+}
-+
-+/*
-+ * Display
-+ */
-+
-+$execView = new CView('experiments.execute');
-+
-+$execView->set('tasklists', exptasklist_getall());
-+$execView->set('targets', $exp_targetlist);
-+$execView->set('currenttarget', 
isset($_REQUEST['target'])?$_REQUEST['target']:reset($exp_targetlist));
-+
-+$execView->render();
-+$execView->show();
-+
-+require_once dirname(__FILE__).'/include/page_footer.php';
-diff --git files.php files.php
-new file mode 100644
-index 0000000..5326ccc
---- /dev/null
-+++ files.php
-@@ -0,0 +1,58 @@
-+<?php
-+
-+require_once dirname(__FILE__).'/include/config.inc.php';
-+require_once dirname(__FILE__).'/include/experiments/inc.php';
-+
-+$page['title'] = _('User Files');
-+$page['file'] = 'files.php';
-+$page['hist_arg'] = array('fileid');
-+
-+//before any headers are written, check if trying to download
-+if(isset($_REQUEST['download']))
-+{
-+    $filename = $_REQUEST['download'];
-+    
-+    expfiles_download($filename);
-+}
-+
-+require_once dirname(__FILE__).'/include/page_header.php';
-+
-+// VAR        TYPE    OPTIONAL        FLAGS   VALIDATION      EXCEPTION
-+/*$fields = array(
-+);
-+check_fields($fields);*/
-+
-+/*
-+ * Actions
-+ */
-+if(isset($_REQUEST['upload']) && isset($_FILES['file']))
-+{
-+    //some validations
-+    if($_FILES["file"]["error"] > 0)
-+        error('File upload error: '.$_FILES["file"]["error"]);
-+    else
-+    {
-+        $filename = $_FILES["file"]["name"];
-+        $fullpath = expfiles_getnewfilepath($filename);
-+        move_uploaded_file($_FILES["file"]["tmp_name"], $fullpath);
-+        
-+        info("File uploaded successfully.");
-+    }
-+}
-+if(isset($_REQUEST['delete']))
-+{
-+    if(expfiles_delete($_REQUEST['delete'])) jsRedirect('files.php');
-+}
-+
-+/*
-+ * Display
-+ */
-+$filesView = new CView('experiments.files');
-+
-+$filesView->set('files', expfiles_getuserfiles());
-+
-+$filesView->render();
-+$filesView->show();
-+
-+
-+require_once dirname(__FILE__).'/include/page_footer.php';
-diff --git images/general/question_mark.png images/general/question_mark.png
-new file mode 100644
-index 
0000000000000000000000000000000000000000..8dee9d00722e31f2c56938ff1e64325fe2f89463
-GIT binary patch
-literal 618
-zcmV-w0+s!VP)<h;3K|address@hidden&`wG00006VoOIv0RI60
-z0RN!9r;`8x010qNS#tmY3zYx>3zY$-s#FjF000McNliru-3bN}3<eTCyMh1!0ryEn
-zK~yNuZPGn#5^)address@hidden)}uBpFD43<address@hidden)ojSQR
-zF1EYWrHz(J6ExJO24Qe21&<Jrk`x0aSNLD=j^lnV)tKlrKil`iaI(4en(ce5e>Wa>
-zC1L?F3IN;tN;address@hidden;@+UBiL|MwS>RVlELY36#GL9%L4uEFVRgHz|&Ag&p-kZI;3
-zt5N^}*xY)}HtlupEL}Z)>address@hidden
-z8T2yWHa*Kll2yaJ{jN^;QVo(-!yH>K(Ti-$<eEW~E9H4hJnTy7Ca_WJvMT`>y_LEw
-zC2_poJ3^tYvG}-1sdA4g1|c4HC9JWa7?nCY4ip2$L!Eu7a=3>CTt4fB+bLkDam=g&
-z!(LlQEGR~;address@hidden;address@hidden>M(qfV*gym#
-z02h1?Y?e8sLmh&J(K)address@hidden|)?A~Aqj7}1+T7aPSR2n<93i}{^2
-z>R?D$cv6_T|D;fA_isF(_4#Ghq>gH`sDB7&hOICGc5`Bwp3QpM(wBCA0DAl<++wDg
-zQ*?v&Wt}p$9(}6z=!dKk*9>~P^;fw6(g>c=sQ*jj7e7}JB#9c$K>z>%07*qoM6N<$
-Eg6%X1fdBvi
-
-literal 0
-HcmV?d00001
-
-diff --git include/blocks.inc.php include/blocks.inc.php
-index 3896140..7b1321a 100644
---- include/blocks.inc.php
-+++ include/blocks.inc.php
-@@ -1401,3 +1401,174 @@ function makeTriggersPopup(array $triggers, array 
$ackParams) {
- 
-       return $popupTable;
- }
-+
-+function make_run_scripts()
-+{
-+      //create big table
-+      $bigTable = new CTableInfo();
-+      
-+    //create table 1
-+    $scriptsTable = new CTableInfo(_('No scripts defined.'));
-+    $scriptsTable->setHeader(array(
-+          _('Name'),
-+          _('Run on Host'),
-+          _('Run on Host Group')
-+    ));
-+    
-+    //get list of scripts
-+    $scripts = API::Script()->get(array(
-+              'output' => array('name')
-+      ));
-+      
-+      //get list of hosts
-+      $hosts = API::Host()->get(array(
-+              'sortfield' => 'name',
-+              'output' => array('name')
-+      ));
-+      
-+      //get list of host groups
-+    $hostgroups = API::HostGroup()->get(array(
-+              'sortfield' => 'name',
-+              'output' => array('name')
-+      ));
-+      
-+      //add rows
-+      foreach($scripts as $script)
-+      {
-+          //create hostgroups combobox & run button
-+        $runForm = new CForm('GET', 'scripts_exec.php');
-+        $runForm->attr("target", "_blank");
-+        $runForm->addItem(new CInput('hidden', 'execute', '1'));
-+        $runForm->addItem(new CInput('hidden', 'scriptid', 
$script['scriptid']));
-+        
-+        $grpsComboBox = new CComboBox('groupid');
-+        foreach($hostgroups as $hostgroup)
-+            $grpsComboBox->addItem(new CComboItem($hostgroup['groupid'], 
$hostgroup['name']));
-+
-+        $runForm->addItem($grpsComboBox);
-+        $runForm->addItem(new CInput('submit', 'submit', 'Run'));
-+        
-+        //create hosts combobox & run button
-+        $runFormHosts = new CForm('GET', 'scripts_exec.php');
-+        $runFormHosts->attr("target", "_blank");
-+        $runFormHosts->addItem(new CInput('hidden', 'execute', '1'));
-+        $runFormHosts->addItem(new CInput('hidden', 'scriptid', 
$script['scriptid']));
-+        
-+        $hostsComboBox = new CComboBox('hostid');
-+        foreach($hosts as $host)
-+            $hostsComboBox->addItem(new CComboItem($host['hostid'], 
$host['name']));
-+
-+        $runFormHosts->addItem($hostsComboBox);
-+        $runFormHosts->addItem(new CInput('submit', 'submit', 'Run'));
-+        
-+        $scriptsTable->addRow(array(
-+                  new CLink($script['name'], 
'scripts.php?form=1&scriptid='.$script['scriptid']),
-+                  $runFormHosts,
-+                  $runForm
-+          ));
-+      }
-+      
-+      //create multiple run form
-+      $multForm = new CFormTable(null, 'scripts_exec.php', 'GET');
-+      
-+      $scriptsCmbbox = new CComboBox('scriptid');
-+      foreach($scripts as $script)
-+              $scriptsCmbbox->addItem(new CComboItem($script['scriptid'], 
$script['name']));
-+      
-+      $hostsListBox = new CListBox('hosts[]', null, 15);
-+      foreach($hosts as $host)
-+        $hostsListBox->addItem(new CComboItem($host['hostid'], 
$host['name']));
-+    
-+    $multForm->addRow($scriptsCmbbox);
-+    $multForm->addRow($hostsListBox);
-+    $multForm->attr("target", "_blank");
-+    $multForm->addRow(new CInput('hidden', 'execute', '1'), new 
CInput('submit', 'submit', 'Run'));
-+    
-+    $bigTable->addRow(array(
-+      $scriptsTable,
-+      $multForm
-+    ));
-+    
-+    return $bigTable;
-+}
-+
-+function template_items_status($template_id)
-+{
-+      //fetch main template    
-+    $options = array(
-+              'templateids' => array($template_id),
-+              'selectItems' => array('status'),
-+              'output' => array('name')
-+      );
-+
-+      $template = API::Template()->get($options);
-+      
-+      $total = 0;
-+      $enabled = 0;
-+      
-+      foreach($template[0]['items'] as $item)
-+      {
-+              $total++;
-+              if($item['status'] == 0) $enabled++;
-+      }
-+      
-+      return array('total' => $total, 'enabled' => $enabled);
-+}
-+
-+function make_manage_monitoring()
-+{
-+    $templates = array(10001, 10176, 10177);
-+    
-+    //fetch important templates
-+    $options = array(
-+              'templateids' => $templates,
-+              'output' => array('name')
-+      );
-+      $templates = API::Template()->get($options);
-+      
-+      //create link/unlink all forms
-+      $linkAllForm = new CForm('POST', 'manage_monitoring.php');
-+      $unlinkAllForm = new CForm('POST', 'manage_monitoring.php');
-+      foreach($templates as $temp)
-+      {
-+              $linkAllForm->addItem(new CInput('hidden', 
'template['.$temp['hostid'].']', $temp['hostid']));
-+              $unlinkAllForm->addItem(new CInput('hidden', 
'template['.$temp['hostid'].']', $temp['hostid']));
-+      }
-+      $linkAllForm->addItem(new CInput('submit', 'submit', 'Enable All'));
-+    $linkAllForm->addItem(new CInput('hidden', 'action', 'enable'));
-+
-+      $unlinkAllForm->addItem(new CInput('submit', 'submit', 'Disable All'));
-+    $unlinkAllForm->addItem(new CInput('hidden', 'action', 'disable'));
-+      
-+      //table that will contain forms
-+      $table = new CTable();
-+      
-+      foreach($templates as $template)
-+      {
-+              $items_status = template_items_status($template['hostid']);
-+              
-+          $r = new CRow();
-+          $r->addItem(new CLabel($template['name'] . ' [' . 
$items_status['enabled'] . '/' . $items_status['total'] . ']'));
-+          
-+          $enableForm = new CForm('POST', 'manage_monitoring.php');
-+          $enableForm->addItem(new CInput('hidden', 
'template['.$template['hostid'].']', $template['hostid']));
-+          $enableForm->addItem(new CInput('submit', 'submit', 'Disable'));
-+        $enableForm->addItem(new CInput('hidden', 'action', 'disable'));
-+          
-+          $disableForm = new CForm('POST', 'manage_monitoring.php');
-+        $disableForm->addItem(new CInput('hidden', 
'template['.$template['hostid'].']', $template['hostid']));
-+      $disableForm->addItem(new CInput('submit', 'submit', 'Enable'));
-+      $disableForm->addItem(new CInput('hidden', 'action', 'enable'));
-+
-+          $r->addItem($enableForm);        
-+          $r->addItem($disableForm);
-+          
-+          $table->addRow($r);
-+      }
-+      $totalRows = new CRow();
-+      $totalRows->addItem($linkAllForm);
-+      $totalRows->addItem($unlinkAllForm);
-+      $table->addRow($totalRows);
-+      
-+      return $table;
-+}
-diff --git include/classes/import/CXmlImport18.php 
include/classes/import/CXmlImport18.php
-index b03a3bc..b101cbf 100644
---- include/classes/import/CXmlImport18.php
-+++ include/classes/import/CXmlImport18.php
-@@ -1003,7 +1003,7 @@ class CXmlImport18 {
-                               $host_db['groups'] = array();
-                               $groups_to_parse = array();
-                               foreach ($groups as $group) {
--                                      $groups_to_parse[] = array('name' => 
$group->nodeValue);
-+                                      $groups_to_parse[] = array('name' => 
trim($group->nodeValue));
-                               }
-                               if (empty($groups_to_parse)) {
-                                       $groups_to_parse[] = array('name' => 
ZBX_DEFAULT_IMPORT_HOST_GROUP);
-@@ -1134,6 +1134,7 @@ class CXmlImport18 {
- 
-                                       $templateLinkage = array();
-                                       foreach ($templates as $template) {
-+                                              $template->nodeValue = 
trim($template->nodeValue);
-                                               $options = array(
-                                                       'filter' => 
array('host' => $template->nodeValue),
-                                                       'output' => 
API_OUTPUT_SHORTEN,
-diff --git include/experiments/conf.php include/experiments/conf.php
-new file mode 100644
-index 0000000..9bef025
---- /dev/null
-+++ include/experiments/conf.php
-@@ -0,0 +1,9 @@
-+<?php
-+
-+$GLOBALS['GPLMT_DIR'] = '/home/omar/workspace/gnunet-planetlab/gplmt/';
-+
-+$GLOBALS['GPLMT_TASKLISTS_DIR'] = $GLOBALS['GPLMT_DIR'].'contrib/tasklists/';
-+$GLOBALS['GPLMT_CONF_DIR'] = $GLOBALS['GPLMT_DIR'].'contrib/configurations/';
-+$GLOBALS['GPLMT_NODES_DIR'] = $GLOBALS['GPLMT_DIR'].'contrib/nodes/';
-+$GLOBALS['GPLMT_RESULTS_DIR'] = $GLOBALS['GPLMT_DIR'].'contrib/results/';
-+$GLOBALS['GPLMT_FILES_DIR'] = $GLOBALS['GPLMT_DIR'].'contrib/files/';
-diff --git include/experiments/config.php include/experiments/config.php
-new file mode 100644
-index 0000000..1e4ed5a
---- /dev/null
-+++ include/experiments/config.php
-@@ -0,0 +1,106 @@
-+<?php
-+
-+function expconfig_update($data)
-+{
-+    //get user editable config
-+    $editable = expconfig_getuserconfig();
-+    
-+    foreach($data as $k => $v)
-+    {
-+        if(!isset($editable[$k])) continue;
-+        $v = trim($v);
-+        $enabled = ($v != '');
-+        
-+        if(($editable[$k]['type'] == 'file') && $enabled)
-+            $v = expfiles_getuserdir().exp_cleanfilename($v);
-+        
-+        expdb_update('exp_userconfig',
-+            array('value' => $v, 'enabled' => strval($enabled)),
-+            array('configid' => $k, 'userid' => CWebUser::$data['userid']));
-+    }
-+    
-+    expconfig_writefile();
-+}
-+
-+function expconfig_getconfigbyname($configname)
-+{
-+    $uid = CWebUser::$data['userid'];
-+    $sql = "SELECT exp_userconfig.value, exp_userconfig.enabled
-+        FROM exp_config, exp_userconfig
-+        WHERE exp_config.configid = exp_userconfig.configid
-+        AND exp_config.name = '$configname'
-+        AND exp_userconfig.userid = $uid";
-+    $result = DBfetchArray(DBselect($sql));
-+    if(count($result) == 0) return null;
-+    if(!$result[0]['enabled']) return null;
-+    return $result[0]['value'];
-+}
-+
-+function expconfig_getuserconfig($editableOnly = true)
-+{
-+    $uid = CWebUser::$data['userid'];
-+    $sql = "SELECT u.configid, c.section, c.name, c.label, c.description, 
c.type, u.value
-+            FROM exp_config c, exp_userconfig u
-+            WHERE c.configid = u.configid
-+            AND c.user_editable = 1
-+            AND u.userid = $uid
-+            ORDER BY c.section, c.configid";
-+    return DBfetchArrayAssoc(DBselect($sql), 'configid');
-+}
-+
-+function expconfig_getenum($configid)
-+{
-+    return expdb_select('exp_configenum', array('configid' => $configid));
-+}
-+
-+function expconfig_writefile()
-+{
-+    $uid = CWebUser::$data['userid'];
-+    $sql = "SELECT c.section, c.name, u.value
-+            FROM exp_config c, exp_userconfig u
-+            WHERE c.configid = u.configid
-+            AND u.enabled = 1
-+            AND u.userid = $uid
-+            ORDER BY c.section";
-+    $conf = DBfetchArray(DBselect($sql));
-+    
-+    $filename = $GLOBALS['GPLMT_CONF_DIR'].strval($uid);
-+    $f = fopen($filename, 'w+');
-+    $current_sec = '';
-+    
-+    foreach($conf as $c)
-+    {
-+        if($c['section'] != $current_sec)
-+        {
-+            $current_sec = $c['section'];
-+            fwrite($f, "[$current_sec]\n");
-+        }
-+        $k = $c['name'];
-+        $v = $c['value'];
-+        fwrite($f, "$k = $v\n");
-+    }
-+    fclose($f);
-+}
-+
-+function expconfig_verifyuserconfig()
-+{
-+    $uid = CWebUser::$data['userid'];
-+    $default_config = expdb_select('exp_config', array(), 'configid');
-+    $user_config = expdb_select('exp_userconfig', array('userid' => $uid), 
'configid');
-+    
-+    if(count($default_config) == count($user_config)) return;
-+    
-+    foreach($default_config as $dc_k => $dc)
-+    {
-+        if(isset($user_config[$dc_k])) continue;
-+        
-+        $newval = $dc['default_value'];
-+        if($dc['name'] == 'userdir') //special cases, user specific
-+            $newval = expfiles_getuserdir();
-+        $enabled = strval(($newval != ''));
-+        
-+        expdb_insert('exp_userconfig',
-+            array('configid' => $dc_k, 'userid' => $uid, 'value' => $newval, 
'enabled' => $enabled));
-+    }
-+    expconfig_writefile();
-+}
-diff --git include/experiments/db.php include/experiments/db.php
-new file mode 100644
-index 0000000..14f1b7c
---- /dev/null
-+++ include/experiments/db.php
-@@ -0,0 +1,85 @@
-+<?php
-+
-+function expdb_genwhere($where)
-+{
-+    if(sizeof($where) == 0) return '';
-+    
-+    $where_str = ' WHERE ';
-+    
-+    $first = true;
-+    foreach($where as $k => $v)
-+    {
-+        if(!$first) $where_str .= ' AND ';
-+        else $first = false;
-+        $where_str .= $k.'=';
-+        if(is_string($v))
-+            $where_str .= ("'".mysql_real_escape_string(trim($v))."'");
-+        else
-+            $where_str .= $v;
-+    }
-+    
-+    return $where_str;
-+}
-+
-+function expdb_insert($table, $data)
-+{
-+    $keys_str = implode(',', array_keys($data));
-+    
-+    $vals = array();
-+    foreach($data as $v)
-+    {
-+        if(is_string($v)) $vals[] = 
"'".mysql_real_escape_string(trim($v))."'";
-+        else $vals[] = $v;
-+    }
-+    
-+    $vals_str = implode(',', $vals);
-+    
-+    $sql = "INSERT INTO $table ($keys_str) VALUES ($vals_str)";
-+    
-+    DBexecute($sql);
-+    return mysql_insert_id(); #TODO: mysql specific, need to be changed to be 
generic
-+}
-+
-+function expdb_update($table, $data, $where)
-+{
-+    $set_str = '';
-+    $first = true;
-+    foreach($data as $k => $v)
-+    {
-+        if(!$first) $set_str .= ',';
-+        else $first = false;
-+        $set_str .= $k.'=';
-+        if(is_string($v))
-+            $set_str .= ("'".mysql_real_escape_string(trim($v))."'");
-+        else
-+            $set_str .= $v;
-+    }
-+    
-+    $where_str = expdb_genwhere($where);
-+    
-+    $sql = "UPDATE $table SET $set_str $where_str";
-+    
-+    return DBexecute($sql);
-+}
-+
-+
-+function expdb_select($table, $where, $assocField = null)
-+{
-+    $where_str = expdb_genwhere($where);
-+    
-+    $sql = "SELECT * FROM $table $where_str";
-+    
-+    if($assocField)
-+        return DBfetchArrayAssoc(DBselect($sql), $assocField);
-+    else
-+        return DBfetchArray(DBselect($sql));
-+}
-+
-+function expdb_delete($table, $where)
-+{
-+    $where_str = expdb_genwhere($where);
-+    
-+    $sql = "DELETE FROM $table $where_str";
-+    
-+    return DBexecute($sql);
-+}
-diff --git include/experiments/files.php include/experiments/files.php
-new file mode 100644
-index 0000000..a2f5fe8
---- /dev/null
-+++ include/experiments/files.php
-@@ -0,0 +1,82 @@
-+<?php
-+
-+/*
-+ * Get the full path for the directory containing the user personal file
-+ */
-+function expfiles_getuserdir()
-+{
-+    $uid = CWebUser::$data['userid'];
-+    $dir = $GLOBALS['GPLMT_FILES_DIR'].strval($uid).'/';
-+    if(!file_exists($dir)) mkdir($dir);
-+    return $dir;
-+}
-+
-+/*
-+ * Returns an array with the names of files inside the user personal directory
-+ */
-+function expfiles_getuserfiles()
-+{
-+    $dirpath = expfiles_getuserdir();
-+    
-+    $res = scandir($dirpath);
-+    $res = array_diff($res, array('.', '..'));
-+    return $res;
-+}
-+
-+/*
-+ * Given a file name for a new file to be uploaded, returns a full path 
-+ * with the same or modified filename if already exists
-+ */
-+function expfiles_getnewfilepath($filename = 'new')
-+{
-+    $filename = exp_cleanfilename($filename);
-+    $dirpath = expfiles_getuserdir();
-+    
-+    $parts = explode('.', $filename);
-+    $orig = $parts[0];
-+    
-+    $counter = 0;
-+    while(file_exists($dirpath.implode('.', $parts)))
-+    {
-+        $parts[0] = $orig.strval($counter);
-+        $counter++;
-+    }
-+    
-+    return $dirpath.implode('.', $parts);
-+}
-+
-+function expfiles_delete($filename)
-+{
-+    $filename = exp_cleanfilename($filename);
-+    $fullpath = expfiles_getuserdir().$filename;
-+    if(file_exists($fullpath)) unlink($fullpath);
-+    return true;
-+}
-+
-+function expfiles_download($filename)
-+{
-+    $filename = exp_cleanfilename($filename);
-+    $fullpath = expfiles_getuserdir().$filename;
-+    if(!file_exists($fullpath))
-+    {
-+        error("File doesn't exist");
-+        return false;
-+    }
-+    
-+    $size = filesize($fullpath);
-+    $mime_type="application/force-download";
-+    
-+    //@ob_end_clean();
-+    
-+    header('Content-Type: ' . $mime_type);
-+    header('Content-Disposition: attachment; filename="'.$filename.'"');
-+    header("Content-Transfer-Encoding: binary");
-+    header('Accept-Ranges: bytes');
-+    header("Cache-control: private");
-+    header('Pragma: private');
-+    header('Content-Length: ' . $size);
-+    ob_clean();
-+    flush();
-+    readfile($fullpath); 
-+    exit;
-+}
-diff --git include/experiments/inc.php include/experiments/inc.php
-new file mode 100644
-index 0000000..0823b39
---- /dev/null
-+++ include/experiments/inc.php
-@@ -0,0 +1,50 @@
-+<?php
-+
-+require_once dirname(__FILE__).'/conf.php';
-+require_once dirname(__FILE__).'/db.php';
-+require_once dirname(__FILE__).'/tasklist.php';
-+require_once dirname(__FILE__).'/run.php';
-+require_once dirname(__FILE__).'/files.php';
-+require_once dirname(__FILE__).'/config.php';
-+require_once dirname(__FILE__).'/nodes.php';
-+require_once dirname(__FILE__).'/targets.php';
-+
-+define('EXP_OK', '0');
-+define('EXP_ERR_GPLMT_DIR', '1');
-+define('EXP_ERR_PERMISSION', '2');
-+define('EXP_ERR_INVALID_TARGET', '3');
-+
-+
-+function exp_cleanfilename($filename)
-+{
-+    return preg_replace("/[^a-z0-9\.]/", "", strtolower($filename));
-+}
-+
-+
-+function exp_gettargets()
-+{
-+    $cmd = 'python '.$GLOBALS['GPLMT_DIR'].'gplmt/Targets.py';
-+    $res = array();
-+    exec($cmd, $res);
-+    return $res;
-+}
-+
-+function exp_verifygplmtdir()
-+{
-+    if(!file_exists($GLOBALS['GPLMT_DIR'].'gplmt.py'))
-+    {
-+        error('GPLMT path invalid!');
-+        return false;
-+    }
-+    
-+    if(!file_exists($GLOBALS['GPLMT_TASKLISTS_DIR'])) 
mkdir($GLOBALS['GPLMT_TASKLISTS_DIR']);
-+    if(!file_exists($GLOBALS['GPLMT_CONF_DIR'])) 
mkdir($GLOBALS['GPLMT_CONF_DIR']);
-+    if(!file_exists($GLOBALS['GPLMT_NODES_DIR'])) 
mkdir($GLOBALS['GPLMT_NODES_DIR']);
-+    if(!file_exists($GLOBALS['GPLMT_RESULTS_DIR'])) 
mkdir($GLOBALS['GPLMT_RESULTS_DIR']);
-+    if(!file_exists($GLOBALS['GPLMT_FILES_DIR'])) 
mkdir($GLOBALS['GPLMT_FILES_DIR']);
-+    
-+    return true;
-+}
-+
-+exp_verifygplmtdir();
-+expconfig_verifyuserconfig();
-diff --git include/experiments/nodes.php include/experiments/nodes.php
-new file mode 100644
-index 0000000..08a4f22
---- /dev/null
-+++ include/experiments/nodes.php
-@@ -0,0 +1,88 @@
-+<?php
-+
-+function expnodes_getbyrunid($run_id)
-+{
-+    $run_id = mysql_real_escape_string($run_id);
-+    
-+    $sql = "SELECT exp_host.hostid, exp_host.host
-+            FROM exp_runnode, exp_host
-+            WHERE exp_runnode.hostid = exp_host.hostid
-+            AND exp_runnode.runid = $run_id";
-+    
-+    return DBfetchArray(DBselect($sql));
-+}
-+
-+function expnodes_writefile($nodes, $run_id)
-+{
-+    $nodes_file = $GLOBALS['GPLMT_NODES_DIR'].$run_id;
-+    
-+    $f = fopen($nodes_file, 'w+');
-+    foreach($nodes as $n) fwrite($f, "$n\n");
-+    fclose($f);
-+}
-+
-+function expnodes_gethosts($target)
-+{
-+    $userid = CWebUser::$data['userid'];
-+    return expdb_select('exp_host', array('userid' => $userid, 'target' => 
$target));
-+}
-+
-+function expnodes_gethostbyid($hostid)
-+{
-+    $res = expdb_select('exp_host', array('hostid' => $hostid));
-+    if(count($res) == 0) return null;
-+    return $res[0];
-+}
-+
-+function expnodes_gethostinterface($hostid)
-+{
-+    $h = API::Host()->get(array(
-+        'hostids' => $hostid,
-+        'output' => array(),
-+        'selectInterfaces' => API_OUTPUT_EXTEND
-+    ));
-+    
-+    if(count($h) == 0) return '';
-+    foreach($h[0]['interfaces'] as $i)
-+    {
-+        if($i['main'] == 1)
-+        {
-+            if($i['useip'] == 1) return $i['ip'];
-+            else return $i['dns'];
-+        }
-+    }
-+}
-+
-+function expnodes_getzabbixnodes()
-+{
-+    $hosts = API::Host()->get(array(
-+        'output' => array('hostid', 'host'),
-+        'selectInterfaces' => API_OUTPUT_EXTEND
-+    ));
-+    
-+    $nodes = array();
-+    
-+    foreach($hosts as $h)
-+    {
-+        $n = array();
-+        $n['hostid'] = $h['hostid'];
-+        $n['host'] = $h['host'];
-+        
-+        foreach($h['interfaces'] as $i)
-+        {
-+            if($i['main'] == 1)
-+            {
-+                $n['interfaceid'] = $i['interfaceid'];
-+                if($i['useip'] == 1) $n['interface'] = $i['ip'];
-+                else $n['interface'] = $i['dns'];
-+                
-+                break;
-+            }
-+        }
-+        
-+        $nodes[] = $n;
-+    }
-+    
-+    return $nodes;
-+}
-+
-diff --git include/experiments/run.php include/experiments/run.php
-new file mode 100644
-index 0000000..c0d0700
---- /dev/null
-+++ include/experiments/run.php
-@@ -0,0 +1,290 @@
-+<?php
-+
-+define('EXP_STATUS_FAILED', -1);
-+define('EXP_STATUS_NOT_STARTED', 0);
-+define('EXP_STATUS_RUNNING', 1);
-+define('EXP_STATUS_DONE_WITH_ERRORS', 2);
-+define('EXP_STATUS_DONE_SUCCESSFULLY', 10);
-+
-+function exprun_getstatusstring($status)
-+{
-+    switch($status)
-+    {
-+        case -1:
-+            return "Failed";
-+        case 0:
-+            return "Not started";
-+        case 1:
-+            return "Running";
-+        case 2:
-+            return "Done with errors";
-+        case 10:
-+            return "Done successfully";
-+        default:
-+            return "Undefined status";
-+    }
-+}
-+
-+function exprun_getall($extended = false, $string_status = true)
-+{
-+    exprun_updateresults(); //update database with any new results
-+
-+    $where['userid'] = intval(CWebUser::$data['userid']);
-+
-+    $res = expdb_select('exp_run', $where);
-+    
-+    for($i = 0; $i < sizeof($res); $i++)
-+    {
-+        $sql = "SELECT exp_runnode.*, exp_host.host as interface FROM 
exp_runnode, exp_host
-+                WHERE exp_runnode.runid = ".$res[$i]['runid']."
-+                AND exp_runnode.hostid = exp_host.hostid
-+                ORDER BY exp_runnode.status DESC, exp_runnode.percentage 
DESC, exp_host.host ASC";
-+        $nodes = DBfetchArray(DBselect($sql));
-+        
-+        if($string_status)
-+            $res[$i]['status'] = exprun_getstatusstring($res[$i]['status']);
-+        
-+        for($j = 0; $j < sizeof($nodes); $j++)
-+        {
-+            if($string_status)
-+                $nodes[$j]['status'] = 
exprun_getstatusstring($nodes[$j]['status']);
-+        }
-+        
-+        $res[$i]['nodes'] = $nodes;
-+    }
-+    
-+    return $res;
-+}
-+
-+function exprun_updateresults()
-+{
-+    $running = expdb_select('exp_run', array('status' => 1));
-+    foreach($running as $r)
-+    {
-+        $updates = exprun_parseresult($r['runid']);
-+        expdb_update('exp_run', array('status' => $updates['status'], 
'percentage' => $updates['percentage']), array('runid' => $r['runid']));
-+        foreach($updates['nodes_results'] as $nr)
-+        {
-+            expdb_update('exp_runnode',
-+                array('status' => $nr['status'], 'percentage' => 
$nr['percentage'], 'log' => $nr['log']),
-+                array('runid' => $r['runid'], 'hostid' => $nr['hostid']));
-+        }
-+    }
-+}
-+
-+function exprun_pidrunning($pid)
-+{
-+    $cmd = "ps --no-headers -p ".$pid;
-+    $res = exec($cmd);
-+    return !empty($res);
-+}
-+
-+function exprun_calculatestatus($percentage, $running, $failure)
-+{
-+    if($percentage < 100) $status = ($running) ? EXP_STATUS_RUNNING : 
EXP_STATUS_FAILED;
-+    else $status = ($failure) ? EXP_STATUS_DONE_WITH_ERRORS : 
EXP_STATUS_DONE_SUCCESSFULLY;
-+    return $status;
-+}
-+
-+function exprun_parseresult($run_id)
-+{
-+    $prog = 0;
-+    $total = 1;
-+    $failure = false;
-+    $nodes_results = array();
-+    
-+    //Read metadata
-+    $meta = exprun_getbyid($run_id);
-+    
-+    //Check if the process is already running
-+    $running = exprun_pidrunning($meta['pid']);
-+
-+    $results_file = $GLOBALS['GPLMT_RESULTS_DIR'].$run_id;
-+    if(file_exists($results_file))
-+    {
-+        //Read nodes from DB
-+        $nodes = expnodes_getbyrunid($run_id);
-+
-+        //Read loaded tasks (if available)
-+        if($meta['usetasklist'])
-+            $tasks = exec('grep -Po "(?<=Loaded )\d+(?= tasks)" 
'.$results_file);
-+        else
-+            $tasks = 1;
-+        if(!empty($tasks))
-+        {
-+            $tasks = intval($tasks);
-+
-+            $total = count($nodes) * $tasks;
-+
-+            //for each node, calculate progress from result output    
-+            foreach($nodes as $n)
-+            {
-+                $node_failure = false;
-+                $interface = $n['host'];
-+
-+                $res = array();
-+                exec('grep -Po "'.$interface.'\s*\| .* \| \K.*" 
'.$results_file, $res); //final result
-+                if(count($res) > 0)
-+                {
-+                    if(trim($res[0]) != 'success')
-+                    {
-+                        $failure = true;
-+                        $node_failure = true;
-+                    }
-+                    $node_prog = $tasks;
-+                }
-+                else
-+                {
-+                    //tasks completed for node
-+                    $tasks_completed = array();
-+                    exec('grep -Po "'.$interface.' : Task \'.*\' completed" 
'.$results_file, $tasks_completed);
-+                    $node_prog = count($tasks_completed);
-+                }
-+                
-+                //get all node logs
-+                $node_log_arr = array();
-+                exec("grep -E '^$interface' $results_file", $node_log_arr);
-+                $node_log = implode("\n", $node_log_arr);
-+                
-+                $node_perc = $node_prog * 100 / $tasks;
-+                $nodes_results[] = array('status' => 
exprun_calculatestatus($node_perc, $running, $node_failure),
-+                                    'percentage' => ($running) ? $node_perc : 
100,
-+                                    'log' => $node_log,
-+                                    'hostid' => $n['hostid']);
-+                $prog += $node_prog;
-+            }
-+        }
-+    }
-+    
-+    $perc = $prog * 100 / $total; //percentage done
-+    $status = exprun_calculatestatus($perc, $running, $failure); //total 
status
-+    
-+    return array('status' => $status, 'percentage' => ($running) ? $perc : 
100, 'nodes_results' => $nodes_results);
-+}
-+
-+function exprun_new($target, $params, $usetasklist, $tasklist, $cmd)
-+{
-+    if(!exp_verifygplmtdir()) return EXP_ERR_GPLMT_DIR;
-+    if($usetasklist == 1 && exptasklist_allowed($tasklist) == 0) return 
EXP_ERR_PERMISSION;
-+    
-+    //create run record
-+    $run_data = array();
-+    $run_data['usetasklist'] = $usetasklist;
-+    if($usetasklist == 1)
-+        $run_data['tasklistid'] = $tasklist;
-+    else
-+        $run_data['command'] = $cmd;
-+    $run_data['userid'] = intval(CWebUser::$data['userid']);
-+    $run_data['target'] = $target;
-+    
-+    $run_id = expdb_insert('exp_run', $run_data);
-+
-+    //create run-nodes records
-+    switch($target)
-+    {
-+        case 'ssh':
-+        case 'planetlab':
-+            $hostnames = array();
-+            foreach($params as $h) //get hostnames and save to DB
-+            {
-+                $hostinfo = expnodes_gethostbyid($h); $hostnames[] = 
$hostinfo['host'];
-+                expdb_insert('exp_runnode', array('runid' => $run_id, 
'hostid' => $h, 'target' => $target));
-+            }
-+            //write GPLMT nodes file
-+            expnodes_writefile($hostnames, $run_id);
-+            break;
-+            
-+        default: //invalid target
-+            expdb_delete('exp_run', array('runid' => $run_id));
-+            return EXP_ERR_INVALID_TARGET;
-+    }
-+    
-+    exprun_gplmt($run_id);
-+    
-+    return EXP_OK;
-+}
-+
-+function exprun_getbyid($run_id)
-+{
-+    $res = expdb_select('exp_run', array('runid' => $run_id));
-+    return $res[0];
-+}
-+
-+function exprun_rerun($run_id)
-+{
-+    $meta = exprun_getbyid($run_id);
-+    if(exprun_pidrunning($meta['pid'])) return;
-+    
-+    exprun_gplmt($run_id);
-+}
-+
-+function exprun_checkpermission($run_id)
-+{
-+    if(CWebUser::$data['type'] == 3) return true;
-+    
-+    $res = expdb_select('exp_run', array('userid' => 
CWebUser::$data['userid'], 'runid' => $run_id));
-+    
-+    return (sizeof($res) > 0);
-+}
-+
-+function exprun_interrupt($run_id)
-+{
-+    $meta = exprun_getbyid($run_id);
-+    
-+    if(!exprun_checkpermission($run_id)) return;
-+    
-+    $cmd = "kill -15 ".$meta['pid'];
-+    exec($cmd);
-+}
-+
-+function exprun_delete($run_id)
-+{
-+    $meta = exprun_getbyid($run_id);    
-+
-+    //check permissions
-+    if(!exprun_checkpermission($run_id)) return;
-+    
-+    //check if tool still running
-+    if(exprun_pidrunning($meta['pid'])) return;
-+
-+    $n = $GLOBALS['GPLMT_NODES_DIR'].$run_id;
-+    if(file_exists($n)) unlink($n);
-+    $r = $GLOBALS['GPLMT_RESULTS_DIR'].$run_id;
-+    if(file_exists($r)) unlink($r);
-+    
-+    expdb_delete('exp_run', array('runid' => $run_id));
-+    expdb_delete('exp_runnode', array('runid' => $run_id));
-+}
-+
-+function exprun_verifyid($run_id)
-+{
-+    $res = expdb_select('exp_run', array('runid' => $run_id));
-+    return (sizeof($res) > 0);
-+}
-+
-+function exprun_gplmt($run_id)
-+{
-+    $run_data = exprun_getbyid($run_id);
-+    if($run_data['usetasklist'])
-+        $tasklist_data = exptasklist_getbyid($run_data['tasklistid']);
-+    
-+    //compose and run command
-+    $cmd = 'python -u '.$GLOBALS['GPLMT_DIR'].'gplmt.py -V'; // GPLMT
-+    $cmd .= ' -c '.$GLOBALS['GPLMT_CONF_DIR'].CWebUser::$data['userid']; // 
Conf file
-+    $cmd .= ' -n '.$GLOBALS['GPLMT_NODES_DIR'].$run_id; // Nodes file
-+    if($run_data['target'] == 'ssh')
-+        $cmd .= ' -t remote_ssh';
-+    elseif($run_data['target'] == 'planetlab')
-+        $cmd .= ' -t planetlab';
-+    if($run_data['usetasklist'])
-+        $cmd .= ' -l 
'.$GLOBALS['GPLMT_TASKLISTS_DIR'].$tasklist_data['fsname']; // Tasklist file
-+    else
-+        $cmd .= " -C '".$run_data['command']."'"; // Command to run
-+    $cmd .= ' > '.$GLOBALS['GPLMT_RESULTS_DIR'].$run_id; // Results file
-+    $cmd .= ' 2>&1 & echo $!'; // Redirect stderr, run in background and get 
pid
-+    
-+    $pid = system($cmd);
-+
-+    expdb_update("exp_run", array('fullcommand' => $cmd, 'pid' => $pid, 
'status' => EXP_STATUS_RUNNING), array('runid' => $run_id));
-+}
-+
-diff --git include/experiments/targets.php include/experiments/targets.php
-new file mode 100644
-index 0000000..3e3cc79
---- /dev/null
-+++ include/experiments/targets.php
-@@ -0,0 +1,184 @@
-+<?php
-+
-+require_once 'XML/RPC2/Client.php';
-+
-+$exp_targetlist = array(
-+    'SSH' => 'ssh',
-+    'Planetlab' => 'planetlab');
-+
-+/*
-+ * Planetlab
-+ */
-+
-+function exppl_getauth()
-+{
-+    $pl_user = expconfig_getconfigbyname('username');
-+    if(!$pl_user) fatal_error('Please specify planetlab username in config');
-+    $pl_pass = expconfig_getconfigbyname('password');
-+    if(!$pl_pass) fatal_error('Please specify planetlab password in config');
-+    
-+    return array(
-+        "AuthMethod" => 'password',
-+        "Username" => $pl_user,
-+        "AuthString" => $pl_pass
-+        );
-+}
-+
-+function exppl_getclient()
-+{
-+    $pl_api = expconfig_getconfigbyname('api_url');
-+    if(!$pl_api) fatal_error('Please specify planetlab API in config');
-+    
-+    return XML_RPC2_Client::create($pl_api, array('sslverify' => false));
-+}
-+
-+function exppl_getslicename()
-+{
-+    $pl_slice = expconfig_getconfigbyname('slice');
-+    if(!$pl_slice) fatal_error('Please specify planetlab slice in config');
-+    return $pl_slice;
-+}
-+
-+function exppl_getAvailableNodes($page_offset, $page_size, $hostfilter = null)
-+{
-+    $page_offset = intval($page_offset);
-+    $page_size = intval($page_size);
-+
-+    $pl_slice = exppl_getslicename();
-+    $auth = exppl_getauth();
-+    $client = exppl_getclient();
-+    
-+    //get node IDs in slice (for negation)
-+    try
-+    {
-+        $res = $client->GetSlices($auth, $pl_slice, array('node_ids')); 
$node_ids = $res[0]['node_ids'];
-+    }
-+    catch (XML_RPC2_FaultException $e)
-+    {
-+        fatal_error($e->getFaultCode() . ' : ' . $e->getFaultString());
-+    }
-+    
-+    $filter = array('~node_id' => $node_ids,
-+                    '-SORT' => 'hostname',
-+                    '-OFFSET' => $page_offset,
-+                    '-LIMIT' => $page_size);
-+    if($hostfilter) $filter['hostname'] = "*$hostfilter*";
-+    
-+    try
-+    {
-+        return $client->GetNodes($auth, $filter, array('hostname', 
'node_id'));
-+    }
-+    catch (XML_RPC2_FaultException $e)
-+    {
-+        fatal_error($e->getFaultCode() . ' : ' . $e->getFaultString());
-+    }
-+}
-+
-+function exppl_getSliceNodes()
-+{
-+    $pl_slice = exppl_getslicename();
-+    $auth = exppl_getauth();
-+    $client = exppl_getclient();
-+
-+    //get node IDs
-+    try
-+    {
-+        $res = $client->GetSlices($auth, $pl_slice, array('node_ids')); 
$node_ids = $res[0]['node_ids'];
-+    }
-+    catch (XML_RPC2_FaultException $e)
-+    {
-+        fatal_error($e->getFaultCode() . ' : ' . $e->getFaultString());
-+    }
-+    
-+    //get node hostnames + IDs
-+    try
-+    {
-+        $res = $client->GetNodes($auth, $node_ids, array('hostname', 
'node_id'));
-+    }
-+    catch (XML_RPC2_FaultException $e)
-+    {
-+        fatal_error($e->getFaultCode() . ' : ' . $e->getFaultString());
-+    }
-+    $res = exppl_updateSliceNodesDB($res);
-+    return $res;
-+}
-+
-+function exppl_updateSliceNodes($nodes)
-+{
-+    $pl_slice = exppl_getslicename();
-+    $auth = exppl_getauth();
-+    $client = exppl_getclient();
-+    
-+    try
-+    {
-+        $client->UpdateSlice($auth, $pl_slice, array('nodes' => 
array_map('intval', array_values($nodes))));
-+    }
-+    catch (XML_RPC2_FaultException $e)
-+    {
-+        fatal_error($e->getFaultCode() . ' : ' . $e->getFaultString());
-+    }
-+}
-+
-+function exppl_updateSliceNodesDB($nodes)
-+{
-+    if(!is_array($nodes)) return;
-+    
-+    $userid = CWebUser::$data['userid'];
-+    
-+    // No delete so as not to break previous runs
-+    // Insert new hosts not seen before
-+    
-+    for($i = 0; $i < count($nodes); $i++)
-+    {
-+        if(!exppl_getHostByPLNodeId($nodes[$i]['node_id'])) //Does not exist
-+            $nodes[$i]['hostid'] = expdb_insert('exp_host', array('userid' => 
$userid, 'host' => $nodes[$i]['hostname'], 'target' => 'planetlab', 'pl_nodeid' 
=> $nodes[$i]['node_id']));
-+        else
-+            { $res = exppl_getHostByPLNodeId($nodes[$i]['node_id']); 
$nodes[$i]['hostid'] = $res['hostid']; }
-+    }
-+    
-+    return $nodes;
-+}
-+
-+function exppl_getHostByPLNodeId($pl_nodeid)
-+{
-+    $res = expdb_select('exp_host', array('pl_nodeid' => $pl_nodeid));
-+    if(count($res) == 0) return null;
-+    return $res[0];
-+}
-+
-+/*
-+ * SSH
-+ */
-+
-+function expssh_updatehosts($hostlist)
-+{
-+    if(!is_array($hostlist)) return;
-+    
-+    $userid = CWebUser::$data['userid'];
-+    
-+    $old_hostlist = array();
-+    $new_hostlist = array();
-+    foreach($hostlist as $h)
-+    {
-+        $hc = mysql_real_escape_string(trim($h));
-+        if(!$hc) continue;
-+        if(is_numeric($hc))
-+            $old_hostlist[] = $hc;
-+        else //added hosts value is the host itself not an ID
-+            $new_hostlist[] = $hc;
-+    }
-+    
-+    //look for deleted hosts
-+    if(count($old_hostlist) > 0)
-+    {
-+        $sql = 'DELETE FROM exp_host
-+            WHERE userid = '.$userid
-+            .' AND target = "ssh"'
-+            .' AND hostid NOT IN ('.implode(',', $old_hostlist).')';
-+        DBexecute($sql);
-+    }
-+    
-+    //look for new hosts
-+    foreach($new_hostlist as $h)
-+        expdb_insert('exp_host', array('userid' => $userid, 'host' => $h, 
'target' => 'ssh'));
-+}
-diff --git include/experiments/tasklist.php include/experiments/tasklist.php
-new file mode 100644
-index 0000000..adf432c
---- /dev/null
-+++ include/experiments/tasklist.php
-@@ -0,0 +1,292 @@
-+<?php
-+
-+require_once dirname(__FILE__).'/files.php';
-+
-+//default XML elements (for creating empty nods)
-+$exptasklist_defaults = array();
-+$exptasklist_defaults['sequence'] = new SimpleXMLElement('<sequence 
name=""></sequence>');
-+$exptasklist_defaults['run'] = new SimpleXMLElement('<run 
name=""><command></command><arguments></arguments><timeout>0</timeout><expected_return_code>0</expected_return_code><expected_output></expected_output><stop_on_fail>false</stop_on_fail></run>');
-+$exptasklist_defaults['run_per_host'] = new SimpleXMLElement('<run_per_host 
name=""><command_file></command_file><output_prefix></output_prefix><timeout>0</timeout><expected_return_code>0</expected_return_code><expected_output></expected_output><stop_on_fail>false</stop_on_fail></run_per_host>');
-+$exptasklist_defaults['put'] = new SimpleXMLElement('<put 
name=""><source></source><destination></destination><stop_on_fail>false</stop_on_fail></put>');
-+$exptasklist_defaults['get'] = new SimpleXMLElement('<get 
name=""><source></source><destination>./</destination><stop_on_fail>false</stop_on_fail></get>
 ');
-+
-+function exptasklist_addall()
-+{
-+    $sql = "SELECT * FROM exp_tasklist";
-+    $indb = DBfetchArrayAssoc(DBSelect($sql), 'fsname');
-+    
-+    $indir = scandir($GLOBALS['GPLMT_TASKLISTS_DIR']);
-+    
-+    foreach($indir as $i)
-+    {
-+        if(substr($i, -4) != '.xml') continue;
-+        if(isset($indb[$i])) continue;
-+        $name = str_replace('_', ' ', $i);
-+        $name = str_replace('.xml', '', $name);
-+        
-+        expdb_insert('exp_tasklist', array('name' => $name, 'fsname' => $i, 
'userid' => CWebUser::$data['userid'], 'shared' => 1));
-+    }
-+}
-+
-+function exptasklist_getall($editable = false)
-+{
-+    $sql = "SELECT exp_tasklist.*, CONCAT_WS(' ', users.name, users.surname) 
as username
-+            FROM exp_tasklist INNER JOIN users ON exp_tasklist.userid = 
users.userid";
-+    if(!(CWebUser::$data['type'] == 3)) //not super admin
-+    {
-+        $sql .= ' WHERE exp_tasklist.userid = '.CWebUser::$data['userid'];
-+        if(!$editable)
-+            $sql .= ' OR exp_tasklist.shared = 1';
-+    }
-+    
-+    return DBfetchArray(DBselect($sql));
-+}
-+
-+function exptasklist_getbyid($tasklistid)
-+{
-+    $res = expdb_select('exp_tasklist', array('tasklistid' => $tasklistid));
-+    if(count($res) == 0) return null;
-+    return $res[0];
-+}
-+
-+function exptasklist_getcontent($tasklistid)
-+{
-+    $tl_row = exptasklist_getbyid($tasklistid);
-+    if(!$tl_row) return null;
-+    $file = $GLOBALS['GPLMT_TASKLISTS_DIR'].$tl_row['fsname'];
-+    if(!file_exists($file)) return null;
-+    return file_get_contents($file);
-+}
-+
-+/**
-+ * Given a tasklist id, returns 0, 1 or 2 for No access, read, read/write 
respectively
-+ *
-+ * @return int
-+ */
-+function exptasklist_allowed($tasklistid)
-+{
-+    $tl_row = exptasklist_getbyid($tasklistid);
-+    if(!$tl_row) return 0;
-+    if(CWebUser::$data['type'] == 3 || $tl_row['userid'] == 
CWebUser::$data['userid']) return 2;
-+    if($tl_row['shared']) return 1;
-+    return 0;
-+}
-+
-+function exptasklist_delete($tid)
-+{
-+    $meta = exptasklist_getbyid($tid);
-+    if(!$meta)
-+    {
-+        error("Invalid tasklist ID");
-+        return false;
-+    }
-+    $fullFileName = $GLOBALS['GPLMT_TASKLISTS_DIR'].$meta['fsname'];
-+    
-+    //delete from DB
-+    expdb_delete('exp_tasklist', array('tasklistid' => $tid));
-+    
-+    //delete file
-+    if(file_exists($fullFileName)) unlink($fullFileName);
-+    
-+    return true;
-+}
-+
-+function exptasklist_sxmlappend(SimpleXMLElement $to, SimpleXMLElement $from)
-+{
-+    $toDom = dom_import_simplexml($to);
-+    $fromDom = dom_import_simplexml($from);
-+    $newDom = $toDom->appendChild($toDom->ownerDocument->importNode($fromDom, 
true));
-+    return simplexml_import_dom($newDom);
-+}
-+
-+function exptasklist_constructxml($data)
-+{
-+    global $exptasklist_defaults;
-+    
-+    $xml = new SimpleXMLElement('<?xml version="1.0" 
encoding="UTF-8"?><tasklist></tasklist>');
-+    $xml->addAttribute('xsi:noNamespaceSchemaLocation', 
"../tasklist_schema.xsd", "http://www.w3.org/2001/XMLSchema-instance";);
-+    $xml->addChild('options');
-+
-+    //name
-+    if(empty($data['name']))
-+    {
-+        error("Missing name field");
-+        return false;
-+    }
-+    $name = $data['name'];
-+    $xml->addAttribute('name', $name);
-+    
-+    //target
-+    /*if(!empty($data['target']))
-+        $xml->options->addChild('target', $data['target']);*/
-+
-+    //log dir
-+    if(!empty($data['logdir']))
-+        $xml->options->addChild('log_dir', $data['logdir']);
-+    
-+    //index for node components
-+    $nodesIndex = array();
-+    
-+    foreach($data as $k => $v)
-+    {
-+        $parts = explode('_', $k); // field name consists of field type + the 
path to the field (e.g. command_2_1)
-+        $parts_count = count($parts);
-+        if($parts_count == 1 || $parts_count > 3) continue;
-+        
-+        $field = str_replace('$', '_', $parts[0]);
-+        $value = trim($v);
-+        $index = implode('_', array_slice($parts, 1));
-+        
-+        if($field == 'type') //should be the first field in the node, its type
-+        {
-+            if(!array_key_exists($value, $exptasklist_defaults)) continue; 
//invalid type
-+            
-+            if($parts_count == 2) $parent = $xml;
-+            else $parent = $nodesIndex[$parts[1]];
-+            
-+            $newXml = $exptasklist_defaults[$value];
-+            if($value != 'sequence')
-+            {
-+                $newXml['id'] = $parts[$parts_count - 1]; //GPLMT doesn't 
accept ID in sequence but mandatory for others
-+                $newXml['name'] = $newXml['id']; //Name is also mandatory, so 
we set it by the ID unless we get a name from the user later
-+            }
-+            $newXml['enabled'] = 'false'; //Disabled by default unless we get 
the enabled flag from form
-+            
-+            $nodesIndex[$index] = exptasklist_sxmlappend($parent, $newXml);
-+            
-+            
-+            continue;
-+        }
-+        
-+        if(!array_key_exists($index, $nodesIndex)) continue; //problem or 
data element that is not related to the XML
-+        if($field == 'name' && empty($value)) continue;
-+        
-+        $subxml = $nodesIndex[$index];
-+        $type = $subxml->getName();
-+        
-+        //validations:
-+        switch($field)
-+        {
-+            //bool
-+            case 'enabled': case 'stop_on_fail':
-+                $value = strtolower($value);
-+                if($value != 'yes' && $value != 'no')
-+                {
-+                    error("Value for $field should be true or false!");
-+                    return false;
-+                }
-+                $value = ($value == 'yes') ? 'true' : 'false';
-+                break;
-+            
-+            //int
-+            case 'timeout': case 'expected_return_code':
-+                if(!is_numeric($value))
-+                {
-+                    error("Value for $field should be an integer!");
-+                    return false;
-+                }
-+                break;
-+
-+            //file
-+            case 'source':
-+                if($type == 'put')
-+                {
-+                    $value = exp_cleanfilename($value);
-+                }
-+                break;
-+            case 'destination':
-+                if($type == 'get')
-+                {
-+                    $value = './';
-+                }
-+                break;
-+        }
-+        
-+        //writing values
-+        switch($field)
-+        {
-+            //attributes
-+            case 'enabled': case 'name':
-+                $subxml[$field] = $value;
-+                break;
-+            
-+            case 'command': case 'arguments': case 'timeout': case 
'expected_return_code': case 'expected_output':
-+            case 'stop_on_fail': case 'command_file': case 'output_prefix': 
case 'source': case 'destination':
-+                $subxml->$field = $value;
-+                break;
-+            
-+            default:
-+                error("Unknown field: $field");
-+        }
-+    }
-+    
-+    //save the resulting XML to file (formatted)
-+    $dom = dom_import_simplexml($xml)->ownerDocument;
-+    $dom->formatOutput = true;
-+    return $dom->saveXML();
-+}
-+
-+function exptasklist_add($data)
-+{
-+    $xml = exptasklist_constructxml($data);
-+    if(!$xml) return false;
-+    
-+    //name
-+    $name = $data['name'];
-+    
-+    //description
-+    $description = empty($data['description']) ? '' : $data['description'];
-+    
-+    //shared
-+    $shared = false;
-+    $shared = (!empty($data['shared']) && ($data['shared'] == 'yes'));
-+    
-+    //create new fsname
-+    $fsname = str_replace(' ', '_', $name);
-+    $fsname = str_replace('\\', '_', $fsname);
-+    $counter = 0;
-+    while(file_exists($GLOBALS['GPLMT_TASKLISTS_DIR'].$fsname.'.xml'))
-+    {
-+        $fsname .= strval($counter);
-+        $counter++;
-+    }
-+    $fsname .= '.xml';
-+    
-+    //user ID
-+    $userid = CWebUser::$data['userid'];
-+    
-+    //save to file
-+    file_put_contents($GLOBALS['GPLMT_TASKLISTS_DIR'].$fsname, $xml);
-+    
-+    //save to DB
-+    expdb_insert('exp_tasklist',
-+        array('name' => $name, 'description' => $description, 'fsname' => 
$fsname, 'userid' => $userid, 'shared' => intval($shared)));
-+    
-+    return true;
-+}
-+
-+function exptasklist_update($tasklistid, $data)
-+{
-+    $meta = exptasklist_getbyid($tasklistid); //get task meta data from db
-+    
-+    $xml = exptasklist_constructxml($data);
-+    if(!$xml) return false;
-+    
-+    //name
-+    $name = $data['name'];
-+    
-+    //description
-+    $description = empty($data['description']) ? '' : $data['description'];
-+    
-+    //shared
-+    $shared = false;
-+    $shared = (!empty($data['shared']) && ($data['shared'] == 'yes'));
-+    
-+    file_put_contents($GLOBALS['GPLMT_TASKLISTS_DIR'].$meta['fsname'], $xml);
-+    
-+    //update DB
-+    expdb_update('exp_tasklist', array('name' => $name, 'description' => 
$description, 'shared' => intval($shared)),
-+        array('tasklistid' => $tasklistid));
-+    
-+    return true;
-+}
-diff --git include/menu.inc.php include/menu.inc.php
-index 6e27065..51b0d56 100644
---- include/menu.inc.php
-+++ include/menu.inc.php
-@@ -281,6 +281,38 @@ $ZBX_MENU = array(
-                       )
-               )
-       ),
-+      'experiment' => array(
-+              'label'                         => _('Experiments'),
-+              'user_type'                     => USER_TYPE_ZABBIX_ADMIN,
-+              'node_perm'                     => PERM_READ_WRITE,
-+              'default_page_id'       => 0,
-+              'pages' => array(
-+                      array(
-+                              'url' => 'execute.php',
-+                              'label' => _('Deploy & Execute')
-+                      ),
-+                      array(
-+                              'url' => 'results.php',
-+                              'label' => _('Results')
-+                      ),
-+                      array(
-+                              'url' => 'targets.php',
-+                              'label' => _('Targets')
-+                      ),
-+                      array(
-+                              'url' => 'tasklist.php',
-+                              'label' => _('Tasklists')
-+                      ),
-+                      array(
-+                              'url' => 'files.php',
-+                              'label' => _('Files')
-+                      ),
-+                      array(
-+                              'url' => 'conf.php',
-+                              'label' => _('Configuration')
-+                      )
-+              )
-+      ),
-       'login' => array(
-               'label'                                 => _('Login'),
-               'user_type'                             => 0,
-diff --git include/views/administration.script.list.php 
include/views/administration.script.list.php
-index bb42f3f..aab1244 100644
---- include/views/administration.script.list.php
-+++ include/views/administration.script.list.php
-@@ -40,9 +40,18 @@ $scriptsTable->setHeader(array(
-       make_sorting_header(_('Commands'), 'command'),
-       _('User group'),
-       _('Host group'),
--      _('Host access')
-+      _('Host access'),
-+      _('Run on Host Group')
- ));
- 
-+//get list of host groups
-+$hostgroups = API::HostGroup()->get(array(
-+              'not_proxy_host' => 1,
-+              'sortfield' => 'name',
-+              'editable' => true,
-+              'output' => array('name')
-+      ));
-+
- foreach ($this->data['scripts'] as $script) {
-       $scriptid = $script['scriptid'];
- 
-@@ -72,6 +81,18 @@ foreach ($this->data['scripts'] as $script) {
-               $scriptExecuteOn = '';
-       }
- 
-+    //create hostgroups combobox
-+    $runForm = new CForm('GET', 'scripts_exec.php');
-+    $runForm->addItem(new CInput('hidden', 'execute', '1'));
-+    $runForm->addItem(new CInput('hidden', 'scriptid', $script['scriptid']));
-+    
-+    $grpsComboBox = new CComboBox('groupid');
-+    foreach($hostgroups as $hostgroup)
-+        $grpsComboBox->addItem(new CComboItem($hostgroup['groupid'], 
$hostgroup['name']));
-+
-+    $runForm->addItem($grpsComboBox);
-+    $runForm->addItem(new CInput('submit', 'submit', 'Run'));
-+
-       $scriptsTable->addRow(array(
-               new CCheckBox('scripts['.$script['scriptid'].']', 'no', null, 
$script['scriptid']),
-               new CLink($script['name'], 
'scripts.php?form=1&scriptid='.$script['scriptid']),
-@@ -80,7 +101,8 @@ foreach ($this->data['scripts'] as $script) {
-               zbx_nl2br(htmlspecialchars($script['command'], ENT_COMPAT, 
'UTF-8')),
-               ('' == $script['userGroupName']) ? _('All') : 
$script['userGroupName'],
-               ('' == $script['hostGroupName']) ? _('All') : 
$script['hostGroupName'],
--              ((PERM_READ_WRITE == $script['host_access']) ? _('Write') : 
_('Read'))
-+              ((PERM_READ_WRITE == $script['host_access']) ? _('Write') : 
_('Read')),
-+              $runForm
-       ));
- }
- 
-diff --git include/views/experiments.conf.php 
include/views/experiments.conf.php
-new file mode 100644
-index 0000000..0af85d5
---- /dev/null
-+++ include/views/experiments.conf.php
-@@ -0,0 +1,66 @@
-+<?php
-+
-+$conf = $this->get('conf');
-+
-+$cWidget = new CWidget();
-+
-+$cForm = new CForm('post');
-+$cTable = new CTableInfo();
-+
-+$current_section = '';
-+foreach($conf as $c)
-+{
-+    if($c['section'] != $current_section)
-+    {
-+        $current_section = $c['section'];
-+        $cTable->addRow(strtoupper($current_section));
-+    }
-+    
-+    switch($c['type'])
-+    {
-+        case 'text': case 'integer':
-+            $cInput = new CTextBox($c['configid'], $c['value']);
-+            break;
-+        
-+        case 'password':
-+            $cInput = new CPassBox($c['configid'], $c['value'], 20);
-+            break;
-+        
-+        case 'boolean':
-+            $cHidden = new CInput('hidden', $c['configid'], 'no');
-+            $cChkbox = new CCheckBox($c['configid'], $c['value']);
-+            $cInput = array($cHidden, $cChkbox);
-+            break;
-+        
-+        case 'file':
-+            $userfiles = expfiles_getuserfiles();
-+            $selectedfile = '';
-+            if(!empty($c['value'])) $selectedfile = basename($c['value']);
-+            $cInput = new CComboBox($c['configid']);
-+            $cInput->addItem('', '');
-+            foreach($userfiles as $uf)
-+                $cInput->addItem($uf, $uf, ($selectedfile == $uf)?'yes':null);
-+            break;
-+
-+        case 'enum':
-+            $options = expconfig_getenum($c['configid']);
-+            $cInput = new CComboBox($c['configid']);
-+            foreach($options as $o)
-+                $cInput->addItem($o['value'], $o['label'], ($c['value'] == 
$o['value'])?'yes':null);
-+            break;
-+
-+        default:
-+            $cInput = new CLabel('Invalid type');
-+            break;
-+    }
-+    
-+    $help_image = new CImg('images/general/question_mark.png');
-+    $help_image->attr('title', $c['description']);
-+    
-+    $cTable->addRow(array($c['label'], array($cInput, $help_image)));
-+}
-+$cTable->addRow(new CSubmit('update', 'Update'));
-+
-+$cForm->addItem($cTable);
-+$cWidget->addItem($cForm);
-+return $cWidget;
-diff --git include/views/experiments.execute.php 
include/views/experiments.execute.php
-new file mode 100644
-index 0000000..bc87ce3
---- /dev/null
-+++ include/views/experiments.execute.php
-@@ -0,0 +1,100 @@
-+<?php
-+
-+$targets = $this->get('targets');
-+$currenttarget = $this->get('currenttarget');
-+
-+//Main Form
-+$exec_frm = new CForm();
-+$exec_frm->setName('web.experiment.execute.php.');
-+$exec_frm->attr('id', 'mainfrm');
-+
-+//Main table
-+$main_table = new CTable();
-+
-+//Row 1 - Targets
-+$targets_cmb = new CComboBox('target');
-+foreach($targets as $k => $v)
-+    $targets_cmb->addItem($v, $k, ($v == $currenttarget)?'yes':null);
-+$targets_cmb->attr('onchange', "jQuery('#mainfrm').submit();");
-+
-+$main_table->addRow(new CRow(array(
-+    'Select Target:',
-+    $targets_cmb)));
-+
-+//Row 2 - Target settings
-+$settings_enabled = false;
-+switch($currenttarget)
-+{
-+    case 'ssh':
-+        $settings_enabled = true;
-+        
-+        $sshhosts = expnodes_gethosts('ssh');
-+        $sshhosts_tb = new CTweenBox($exec_frm, 'hosts');
-+        foreach($sshhosts as $sh)
-+            $sshhosts_tb->addItem($sh['hostid'], $sh['host'], true);
-+        
-+        $settings_elm = $sshhosts_tb->get('Selected:', 'Excluded:');
-+        
-+        break;
-+    
-+    case 'planetlab':
-+        $settings_enabled = true;
-+        
-+        $plhosts = exppl_getSliceNodes();
-+        $plhosts_tb = new CTweenBox($exec_frm, 'hosts');
-+        foreach($plhosts as $ph)
-+            $plhosts_tb->addItem($ph['hostid'], $ph['hostname'], true);
-+        
-+        $settings_elm = $plhosts_tb->get('Selected:', 'Excluded:');
-+    
-+        break;
-+    
-+    default:
-+        $settings_enabled = true;
-+        $settings_elm = 'Invalid Target. WHY?';
-+        break;
-+}
-+if($settings_enabled)
-+    $main_table->addRow(new CRow(array(
-+        'Target Settings:',
-+        $settings_elm)));
-+
-+//Row 3 - Tasklists
-+$tasklists = $this->get('tasklists');
-+
-+$tasklists_tbl = new CTable();
-+
-+$tasklists_rad1 = new CRadioButton('usetasklist', '1', 'input radio', null, 
true);
-+$tasklists_rad2 = new CRadioButton('usetasklist', '0', 'input radio');
-+$tasklists_cmb = new CComboBox('tasklist');
-+foreach($tasklists as $t)
-+    $tasklists_cmb->addItem($t['tasklistid'], $t['name']);
-+$tasklists_txt = new CTextBox('cmd');
-+
-+
-+$tasklists_tbl->addRow(
-+array(
-+new CDiv(array(
-+$tasklists_rad1, 'Tasklist:')),
-+$tasklists_cmb));
-+$tasklists_tbl->addRow(
-+array(
-+new CDiv(array(
-+$tasklists_rad2, 'Command:')),
-+$tasklists_txt));
-+
-+$main_table->addRow(new CRow(array(
-+    'Select Tasklist / Command:',
-+    $tasklists_tbl
-+)));
-+
-+
-+$exec_frm->addItem($main_table);
-+
-+/*
-+ * footer
-+ */
-+$run_submit = array(new CSubmit('run', 'Run'));
-+$exec_frm->addItem(makeFormFooter($run_submit));
-+
-+return $exec_frm;
-diff --git include/views/experiments.files.php 
include/views/experiments.files.php
-new file mode 100644
-index 0000000..1fd1203
---- /dev/null
-+++ include/views/experiments.files.php
-@@ -0,0 +1,30 @@
-+<?php
-+
-+$files = $this->get('files');
-+
-+$fWidget = new CWidget();
-+
-+$uploadForm = new CForm('post', null, 'multipart/form-data');
-+$uploadForm->addItem(new CInput('file', 'file'));
-+$uploadForm->addItem(new CSubmit('upload', 'Upload file'));
-+//add maximum size note
-+
-+$fWidget->addPageHeader('USER FILES', $uploadForm);
-+
-+$files_tbl = new CTableInfo('No files added yet.');
-+$files_tbl->setHeader(array('File name', ''));
-+foreach($files as $f)
-+{
-+    //download link
-+    $download_lnk = new CLink($f, '?download='.$f);
-+    
-+    //delete link
-+    $delete_lnk = new CLink('delete', '?delete='.$f);
-+    
-+    $files_tbl->addRow(array($download_lnk, $delete_lnk));
-+    //TODO: add delete, download
-+}
-+
-+$fWidget->addItem($files_tbl);
-+
-+return $fWidget;
-diff --git include/views/experiments.results.php 
include/views/experiments.results.php
-new file mode 100644
-index 0000000..2591b41
---- /dev/null
-+++ include/views/experiments.results.php
-@@ -0,0 +1,63 @@
-+<?php
-+
-+//Main table
-+$main_table = new CTableInfo();
-+
-+$results = $this->get('results');
-+$runid = $this->get('runid'); //if set, one of the runs is selected
-+
-+$main_table->setHeader(array('', 'Status', 'Started On', 'Target', 
'Percentage completed', '', ''));
-+
-+foreach($results as $r)
-+{
-+    $div_actions = new CDiv();
-+    if($r['status'] == 'Running')
-+        $div_actions->addItem(new CLink('interrupt', 
'results.php?interrupt='.$r['runid']));
-+    else
-+    {
-+        $div_actions->addItem(new CLink('delete', 
'results.php?delete='.$r['runid']));
-+        //$div_actions->addItem(new CButtonDelete('Are you sure you want to 
delete?', $r['runid']));
-+        $div_actions->addItem(' | ');
-+        $div_actions->addItem(new CLink('re-run', 
'results.php?rerun='.$r['runid']));
-+    }
-+    
-+    //nodes table
-+    $nodes_table = new CTableInfo();
-+    foreach($r['nodes'] as $n)
-+    {
-+        $nodes_table->addRow(new CRow(array(
-+            $n['interface'],
-+            $n['status'],
-+            $n['percentage'].'%',
-+            new CLink('log', 
'results.php?runid='.$r['runid'].'&hostid='.$n['hostid'])
-+        )));
-+    }
-+    
-+    $main_row = array(
-+        new CButton(null, '+/-', 
"javascript:jQuery('#".$r['runid']."').toggle();"),
-+        $r['status'],
-+        $r['startedon'],
-+        $r['target'],
-+        $r['percentage'].'%',
-+        new CLink('log', 'results.php?runid='.$r['runid']),
-+        $div_actions
-+        );
-+    $main_table->addRow(new CRow($main_row));
-+    $hidden_col = new CCol($nodes_table, null, count($main_row));
-+    $hidden_col->attr('id', $r['runid']);
-+    if(empty($runid) || $runid != $r['runid'])
-+        $hidden_col->attr('style', 'display:none;');
-+    $main_table->addRow(new CRow($hidden_col));
-+}
-+
-+$log = $this->get('log');
-+
-+if(!empty($log))
-+{
-+    $res_txt = new CTextArea(null, $log, array('rows' => substr_count($log, 
"\n") + 1, 'readonly' => 1));
-+    $res_txt->attr('style', 'width:100%;font-size:15px;');
-+    
-+    return new CDiv(array($main_table, 'RESULT:', $res_txt));
-+}
-+else
-+    return $main_table;
-diff --git include/views/experiments.targets.php 
include/views/experiments.targets.php
-new file mode 100644
-index 0000000..af46fba
---- /dev/null
-+++ include/views/experiments.targets.php
-@@ -0,0 +1,90 @@
-+<?php
-+$targetlist = $this->get('targetlist');
-+$default_target = reset($targetlist);
-+$selected_target = $this->get('selected_target');
-+if(!$selected_target) $selected_target = $default_target;
-+
-+//Main form
-+$main_frm = new CForm();
-+$main_frm->setName('web.experiment.targets.php.');
-+$main_frm->attr('id', 'mainfrm');
-+
-+//Main table
-+$main_table = new CTable();
-+
-+//Row 1 - Targets
-+$targets_cmb = new CComboBox('target');
-+foreach($targetlist as $k => $v)
-+    $targets_cmb->addItem($v, $k, ($v == $selected_target)?'yes':null);
-+$targets_cmb->attr('onchange', "jQuery('#mainfrm').submit();");
-+$main_table->addRow(array('Target:', $targets_cmb));
-+
-+//Row 2 - Target edit
-+switch($selected_target)
-+{
-+    case 'ssh':
-+        $ssh_lst = new CListBox('sshhosts[]', null, 12);
-+        $sshhosts = $this->get('sshhosts');
-+        foreach($sshhosts as $sh)
-+            $ssh_lst->addItem($sh['hostid'], $sh['host']);
-+        
-+        $del_btn = new CButton('delsshhost', 'Remove', 
"jQuery('select[name=\"sshhosts[]\"]').find(':selected').remove()");
-+        
-+        $add_txt = new CTextBox('newsshhost', null, 30);
-+        $add_btn =  new CButton('addsshhost', 'Add', 
"jQuery('select[name=\"sshhosts[]\"]').append('<option>'+jQuery('input[name=newsshhost]').val()+'</option>');jQuery('input[name=newsshhost]').val('')");
-+        
-+        $submit_btn = new CSubmit('apply', 'Apply');
-+        $submit_btn->attr('onclick', "jQuery('select[name=\"sshhosts[]\"] 
option').attr('selected', 'yes')");
-+        
-+        $main_table->addRow(array('SSH:', array($ssh_lst, $del_btn)));
-+        $main_table->addRow(array('', array($add_txt, $add_btn)));
-+        $main_table->addRow(array('', $submit_btn));
-+        
-+        break;
-+    
-+    case 'planetlab':
-+        $pagesize = 20;
-+        $pageoffset = intval($this->get('ploffset'));
-+        if(!$pageoffset || $pageoffset < 0) $pageoffset = 0;
-+        $hostfilter = $this->get('plfilter');
-+        if(!$hostfilter) $hostfilter = null;
-+        $slicename = exppl_getslicename();
-+        $slicenodes = exppl_getSliceNodes();
-+        $availnodes = exppl_getAvailableNodes($pageoffset, $pagesize, 
$hostfilter);
-+    
-+        $pl_tb = new CTweenBox($main_frm, 'plnodes');
-+        foreach($slicenodes as $sn)
-+            $pl_tb->addItem($sn['node_id'], $sn['hostname'], true);
-+        foreach($availnodes as $an)
-+            $pl_tb->addItem($an['node_id'], $an['hostname']);
-+        
-+        $filter_frm = new CForm('get');
-+        $filter_frm->attr('id', 'filterfrm');
-+        $filter_tb = new CTextBox('plfilter', $hostfilter);
-+        $filter_tb->attr('id', 'plfilter');
-+        $filter_btn = new CSubmit('filter', 'Filter', 
'jQuery("#ploffset").val(0)');
-+        $page_tb = new CTextBox('ploffset', $pageoffset, 2);
-+        $page_tb->attr('id', 'ploffset');
-+        $prev_btn = new CSubmit('plprev', '<<', 
'jQuery("#ploffset").val(parseInt(jQuery("#ploffset").val(), 10) - 
1);jQuery("#filterfrm").submit();');
-+        $next_btn = new CSubmit('plnext', '>>', 
'jQuery("#ploffset").val(parseInt(jQuery("#ploffset").val(), 10) + 
1);jQuery("#filterfrm").submit();');
-+        $clear_btn = new CSubmit('plclear', 'Clear', 
'jQuery("#ploffset").val(0);jQuery("#plfilter").val("")');
-+        $filter_tbl = new CTable();
-+        $filter_tbl->addRow(array(array($prev_btn, $page_tb, $next_btn)));
-+        $filter_tbl->addRow(array(array('Filter:', $filter_tb, $filter_btn)));
-+        $filter_tbl->addRow(array($clear_btn));
-+        $filter_frm->addItem($filter_tbl);
-+        
-+        $pl_tbl = new CTable();
-+        $pl_tbl->addRow(array($pl_tb->get($slicename, 'Available'), 
$filter_frm));
-+        
-+        $submit_btn = new CSubmit('apply', 'Apply');
-+        
-+        $main_table->addRow(array('Planetlab', $pl_tbl));
-+        $main_table->addRow(array('', $submit_btn));
-+        
-+        break;
-+}
-+
-+$main_frm->addItem($main_table);
-+
-+return $main_frm;
-diff --git include/views/experiments.tasklist.edit.php 
include/views/experiments.tasklist.edit.php
-new file mode 100644
-index 0000000..152cf29
---- /dev/null
-+++ include/views/experiments.tasklist.edit.php
-@@ -0,0 +1,318 @@
-+<?php
-+
-+$new = $this->get('new');
-+
-+if($new)
-+    $xml = new SimpleXMLElement('<?xml version="1.0" 
encoding="UTF-8"?><tasklist></tasklist>');
-+else
-+    $xml = $this->get('xml');
-+
-+//$targets = $this->get('targets');
-+$tid = $this->get('tid');
-+if($new)
-+    $meta = array();
-+else
-+    $meta = $this->get('meta');
-+$exptasklist_defaults = $this->get('exptasklist_defaults');
-+
-+function tlview_parseseq($xml, $postfix)
-+{
-+    $seq_tbl = new CTableInfo('');
-+    $seq_tbl->attr('id', "table$postfix");
-+    
-+    //Top Row:
-+    $btns_div = new CDiv();
-+    //Delete button
-+    $del_btn = new CButton('delete', 'delete', 'javascript: 
jQuery("#row'.$postfix.'").remove()');
-+    //Type (hidden)
-+    $type_hdn = new CInput('hidden', 'type'.$postfix, 'sequence');
-+    $btns_div->addItem($type_hdn);
-+    //Add runs
-+    $run_cmb = new CComboBox('run');
-+    $run_cmb->attr('id', "runs$postfix");
-+    $run_cmb->addItem('run', 'run');
-+    $run_cmb->addItem('run_per_host', 'run_per_host');
-+    $run_cmb->addItem('put', 'put');
-+    $run_cmb->addItem('get', 'get');
-+    $btns_div->addItem($run_cmb);
-+    $js = 'javascript: '; //javascript used to add runs under this sequence
-+    $js .= 'if (typeof window.counter'.$postfix.' === "undefined") 
window.counter'.$postfix.' = '.(count($xml->children())+1).';';
-+    $js .= 'new_node(jQuery("#runs'.$postfix.'").val(), 
"'.$postfix.'_"+counter'.$postfix.', "table'.$postfix.'", 
counter'.$postfix.'%2);';
-+    $js .= 'counter'.$postfix.'++;';
-+    $add_btn = new CButton('add', 'Add', $js);
-+    $btns_div->addItem($add_btn);
-+    //Move up
-+    $mvup_btn = new CButton('mvup', 'Move UP', 'javascript: 
p=jQuery("#row'.$postfix.'").prev(); if(p.attr("id")) 
jQuery("#row'.$postfix.'").insertBefore(p);');
-+    $btns_div->addItem($mvup_btn);
-+    //Move down
-+    $mvdown_btn = new CButton('mvdown', 'Move DOWN', 'javascript: 
n=jQuery("#row'.$postfix.'").next(); if(n.attr("id")) 
jQuery("#row'.$postfix.'").insertAfter(n);');
-+    $btns_div->addItem($mvdown_btn);
-+    
-+    $seq_tbl->addRow(array($del_btn, $btns_div));
-+    
-+    //Sequence attributes
-+    
-+    //Name attribute
-+    $name_tb = new CInput('text', 'name'.$postfix, (string)$xml['name']);
-+    $name_tb->addStyle('width: 50em;');
-+    $seq_tbl->addRow(array('Name:', $name_tb));
-+    
-+    //Enabled attribute
-+    $enabled_chb = new CCheckBox('enabled'.$postfix, 
(((string)$xml['enabled']) == 'false')?'no':'yes');
-+    $seq_tbl->addRow(array('Enabled:', $enabled_chb));
-+    
-+    
-+    $counter = 1;
-+    foreach($xml->children() as $c)
-+    {
-+        $name = trim($c->getName());
-+        $row_postfix = $postfix.'_'.$counter;
-+        $seq_tbl->addRow(tlview_parserun($name, $c, $row_postfix));
-+        $counter++;
-+    }
-+    
-+    //print "<script>var counter$postfix = $counter</script>";
-+    
-+    return new CRow(array('Sequence:', $seq_tbl), null, "row$postfix");
-+}
-+function tlview_parserun($type, $xml, $postfix)
-+{
-+    $run_tbl = new CTableInfo('');
-+    
-+    //common elements
-+    
-+    //Top Row:
-+    $btns_div = new CDiv();
-+    //Delete button
-+    $del_btn = new CButton('delete', 'delete', 'javascript: 
jQuery("#row'.$postfix.'").remove()');
-+    //Type (hidden)
-+    $type_hdn = new CInput('hidden', 'type'.$postfix, $type);
-+    $btns_div->addItem($type_hdn);
-+    //Move up
-+    $mvup_btn = new CButton('mvup', 'Move UP', 'javascript: 
p=jQuery("#row'.$postfix.'").prev(); if(p.attr("id")) 
jQuery("#row'.$postfix.'").insertBefore(p);');
-+    $btns_div->addItem($mvup_btn);
-+    //Move down
-+    $mvdown_btn = new CButton('mvdown', 'Move DOWN', 'javascript: 
n=jQuery("#row'.$postfix.'").next(); if(n.attr("id")) 
jQuery("#row'.$postfix.'").insertAfter(n);');
-+    $btns_div->addItem($mvdown_btn);
-+    
-+    $run_tbl->addRow(array($del_btn, $btns_div));
-+    
-+    //Name attribute
-+    $name_tb = new CInput('text', 'name'.$postfix, (string)$xml['name']);
-+    $name_tb->addStyle('width: 50em;');
-+    $run_tbl->addRow(array('Name:', $name_tb));
-+    
-+    //Enabled attribute
-+    $enabled_chb = new CCheckBox('enabled'.$postfix, 
(((string)$xml['enabled']) == 'false')?'no':'yes');
-+    $run_tbl->addRow(array('Enabled:', $enabled_chb));
-+    
-+    switch($type)
-+    {
-+        case 'run':
-+            //command
-+            $cmd_tb = new CInput('text', 'command'.$postfix, 
(string)$xml->command);
-+            $cmd_tb->addStyle('width: 50em;');
-+            $run_tbl->addRow(array('Command:', $cmd_tb));
-+            
-+            //arguments
-+            $args_tb = new CInput('text', 'arguments'.$postfix, 
(string)$xml->arguments);
-+            $args_tb->addStyle('width: 50em;');
-+            $run_tbl->addRow(array('Arguments:', $args_tb));
-+            
-+            //timeout
-+            $timeout_tb = new CInput('text', 'timeout'.$postfix, 
(string)$xml->timeout);
-+            $run_tbl->addRow(array('Timeout:', $timeout_tb));
-+            
-+            //expected_return_code
-+            $expected_return_code_tb = new CInput('text', 
'expected$return$code'.$postfix, (string)$xml->expected_return_code);
-+            $run_tbl->addRow(array('Expected Return Code:', 
$expected_return_code_tb));
-+            
-+            //expected_output
-+            $expected_output_tb = new CInput('text', 
'expected$output'.$postfix, (string)$xml->expected_output);
-+            $expected_output_tb->addStyle('width: 50em;');
-+            $run_tbl->addRow(array('Expected Output:', $expected_output_tb));
-+            
-+            break;
-+        case 'run_per_host':
-+            //command_file
-+            $command_file_tb = new CInput('text', 'command$file'.$postfix, 
(string)$xml->command_file);
-+            $command_file_tb->addStyle('width: 50em;');
-+            $run_tbl->addRow(array('Command File:', $command_file_tb));
-+            
-+            //output_prefix
-+            $output_prefix_tb = new CInput('text', 'output$prefix'.$postfix, 
(string)$xml->output_prefix);
-+            $output_prefix_tb->addStyle('width: 50em;');
-+            $run_tbl->addRow(array('Output Prefix:', $output_prefix_tb));
-+            
-+            //timeout
-+            $timeout_tb = new CInput('text', 'timeout'.$postfix, 
(string)$xml->timeout);
-+            $run_tbl->addRow(array('Timeout:', $timeout_tb));
-+            
-+            //expected_return_code
-+            $expected_return_code_tb = new CInput('text', 
'expected$return$code'.$postfix, (string)$xml->expected_return_code);
-+            $run_tbl->addRow(array('Expected Return Code:', 
$expected_return_code_tb));
-+            
-+            //expected_output
-+            $expected_output_tb = new CInput('text', 
'expected$output'.$postfix, (string)$xml->expected_output);
-+            $expected_output_tb->addStyle('width: 50em;');
-+            $run_tbl->addRow(array('Expected Output:', $expected_output_tb));
-+        
-+            break;
-+        case 'put':
-+            //source
-+            $userfiles = expfiles_getuserfiles();
-+            $selectedfile = '';
-+            if(!empty($xml->source)) $selectedfile = 
basename((string)$xml->source);
-+            $source_cmb = new CComboBox('source'.$postfix);
-+            foreach($userfiles as $uf)
-+                $source_cmb->addItem($uf, $uf, ($selectedfile == 
$uf)?'yes':null);
-+            $run_tbl->addRow(array('Source:', $source_cmb));
-+            
-+            //destination
-+            $destination_tb = new CInput('text', 'destination'.$postfix, 
(string)$xml->destination);
-+            $destination_tb->addStyle('width: 50em;');
-+            $run_tbl->addRow(array('Destination:', $destination_tb));
-+        
-+            break;
-+        case 'get':
-+            //source
-+            $source_tb = new CInput('text', 'source'.$postfix, 
(string)$xml->source);
-+            $source_tb->addStyle('width: 50em;');
-+            $run_tbl->addRow(array('Source:', $source_tb));
-+            
-+            //destination (removed because now all files should go to the 
user specific folder)
-+            /*$destination_tb = new CInput('text', 'destination'.$postfix, 
(string)$xml->destination);
-+            $destination_tb->addStyle('width: 50em;');
-+            $run_tbl->addRow(array('Destination:', $destination_tb));*/
-+            break;
-+    }
-+    
-+    //Stop on fail
-+    $stop_on_fail_chb = new CCheckBox('stop$on$fail'.$postfix, 
(((string)$xml->stop_on_fail) == 'false')?'no':'yes');
-+    $run_tbl->addRow(array('Stop on fail:', $stop_on_fail_chb));
-+    
-+    return new CRow(array("$type:", $run_tbl), null, "row$postfix");
-+    return $run_tbl;
-+}
-+
-+//print_r($xml);
-+
-+if($new)
-+    $main_frm = new CForm('post', 'tasklist.php?new=new');
-+else
-+    $main_frm = new CForm('post', 'tasklist.php?tid='.$tid);
-+$main_tbl = new CTableInfo('');
-+$main_tbl->attr('id', 'table_main');
-+
-+//Top Row:
-+$btns_div = new CDiv();
-+//'Add run' (all types)
-+$run_cmb = new CComboBox('run');
-+$run_cmb->attr('id', 'runs_main');
-+$run_cmb->addItem('sequence', 'sequence');
-+$run_cmb->addItem('run', 'run');
-+$run_cmb->addItem('run_per_host', 'run_per_host');
-+$run_cmb->addItem('put', 'put');
-+$run_cmb->addItem('get', 'get');
-+$btns_div->addItem($run_cmb);
-+$add_btn = new CButton('add', 'Add', "javascript: 
new_node(jQuery('#runs_main').val(), '_'+counter, 'table_main', counter%2); 
counter++;");
-+$btns_div->addItem($add_btn);
-+
-+$main_tbl->addRow(array('', $btns_div));
-+
-+//name attribute
-+$name_tb = new CInput('text', 'name', (string)$xml['name']);
-+$name_tb->addStyle('width: 50em;');
-+$main_tbl->addRow(array('Name:', $name_tb));
-+
-+//description
-+$desc_ta = new CTextArea('description', 
(empty($meta['description']))?'':$meta['description']);
-+$main_tbl->addRow(array('Description:', $desc_ta));
-+
-+//shared
-+$shared_chb = new CCheckBox('shared', (empty($meta['shared']))?'no':'yes');
-+$main_tbl->addRow(array('Shared:', $shared_chb));
-+
-+//option 1 - Target
-+/*$selected_target = 
isset($xml->options->target)?trim((string)$xml->options->target):'remote_ssh';
-+$target_cmb = new CComboBox('target');
-+foreach($targets as $t)
-+    $target_cmb->addItem($t, $t, ($selected_target == $t)?'yes':null);
-+$main_tbl->addRow(array('Target:', $target_cmb));*/
-+
-+//option 2 - Log dir
-+$log_dir = 
isset($xml->options->log_dir)?trim((string)$xml->options->log_dir):'';
-+$log_dir_tb = new CInput('text', 'log$dir', $log_dir);
-+$log_dir_tb->addStyle('width: 50em;');
-+$main_tbl->addRow(array('Log Dir:', $log_dir_tb));
-+
-+$counter = 1;
-+foreach($xml->children() as $c)
-+{
-+    $name = trim($c->getName());
-+    if($name == 'sequence')
-+    {
-+        $main_tbl->addRow(tlview_parseseq($c, '_'.$counter));
-+        $counter++;
-+    }
-+    elseif($name == 'run' || $name == 'run_per_host' || $name == 'put' || 
$name == 'get')
-+    {
-+        $main_tbl->addRow(tlview_parserun($name, $c, '_'.$counter));
-+        $counter++;
-+    }
-+}
-+
-+$main_frm->addItem($main_tbl);
-+
-+//$main_frm->addItem(new CInput('hidden', 'tid', $tid));
-+if($new)
-+    $main_frm->addItem(new CSubmit('add', 'Add'));
-+else
-+    $main_frm->addItem(new CSubmit('update', 'Update'));
-+
-+/*print "TESTING:<br/>";
-+$tmp = tlview_parserun('run', $default_run, '_100');
-+print $tmp->toString();
-+print "END TESTING";*/
-+
-+
-+?>
-+
-+<script>
-+var counter = <?=$counter?>;
-+
-+function new_node(type, postfix, table_id, parity)
-+{
-+var html = '';
-+switch(type)
-+{
-+case 'sequence':
-+html = '<?php print tlview_parseseq($exptasklist_defaults["sequence"], 
"%placeholder%"); ?>';
-+break;
-+case 'run':
-+html = '<?php print tlview_parserun("run", $exptasklist_defaults["run"], 
"%placeholder%"); ?>';
-+break;
-+case 'run_per_host':
-+html = '<?php print tlview_parserun("run_per_host", 
$exptasklist_defaults["run_per_host"], "%placeholder%"); ?>';
-+break;
-+case 'put':
-+html = '<?php print tlview_parserun("put", $exptasklist_defaults["put"], 
"%placeholder%"); ?>';
-+break;
-+case 'get':
-+html = '<?php print tlview_parserun("get", $exptasklist_defaults["get"], 
"%placeholder%"); ?>';
-+break;
-+}
-+
-+html = html.replace(/%placeholder%/g, postfix);
-+jQuery('#'+table_id).append(html);
-+var cl = (parity == 0)?'even_row':'odd_row';
-+jQuery('#row'+postfix).addClass(cl);
-+jQuery('#row'+postfix).attr('origclass', cl);
-+jQuery('#name'+postfix).focus();
-+}
-+
-+</script>
-+
-+<?php
-+
-+return $main_frm;
-diff --git include/views/experiments.tasklist.php 
include/views/experiments.tasklist.php
-new file mode 100644
-index 0000000..e6e0ed8
---- /dev/null
-+++ include/views/experiments.tasklist.php
-@@ -0,0 +1,41 @@
-+<?php
-+
-+$tasklists = $this->get('tasklists');
-+
-+$tlWidget = new CWidget();
-+
-+$createForm = new CForm('get');
-+$createForm->addItem(new CSubmit('new', 'Create tasklist'));
-+
-+$tlWidget->addPageHeader('CONFIGURATION OF TASKLISTS', $createForm);
-+
-+//main form
-+$tlForm = new CForm('get');
-+$tlForm->setName('tasklistForm');
-+
-+//main table
-+$tlTable = new CTableInfo('No tasklists defined.');
-+$tlTable->setHeader(array('Name', 'Description', 'User', 'Shared', ''));
-+
-+foreach($tasklists as $tl)
-+{
-+    //Name link
-+    $name_lnk = new CLink($tl['name'], '?tid='.$tl['tasklistid']);
-+    
-+    //Delete link
-+    $del_btn = new CButtonDelete('Are you sure you want to delete this 
tasklist?', $tl['tasklistid']);
-+    
-+    $tlTable->addRow(array(
-+        $name_lnk,
-+        ($tl['description'])?$tl['description']:'',
-+        $tl['username'],
-+        ($tl['shared'])?'Yes':'No',
-+        $del_btn
-+        ));
-+}
-+
-+$tlForm->addItem($tlTable);
-+
-+$tlWidget->addItem($tlForm);
-+
-+return $tlWidget;
-diff --git include/views/general.script.execute-parallel.php 
include/views/general.script.execute-parallel.php
-new file mode 100644
-index 0000000..4bc5aca
---- /dev/null
-+++ include/views/general.script.execute-parallel.php
-@@ -0,0 +1,54 @@
-+<?php
-+/*
-+** Zabbix
-+** Copyright (C) 2000-2011 Zabbix SIA
-+**
-+** This program is free software; you can redistribute it and/or modify
-+** it under the terms of the GNU General Public License as published by
-+** the Free Software Foundation; either version 2 of the License, or
-+** (at your option) any later version.
-+**
-+** This program is distributed in the hope that it will be useful,
-+** but WITHOUT ANY WARRANTY; without even the implied warranty of
-+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+** GNU General Public License for more details.
-+**
-+** You should have received a copy of the GNU General Public License
-+** along with this program; if not, write to the Free Software
-+** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
USA.
-+**/
-+
-+
-+//javascript item
-+$js = new CJSscript();
-+
-+$numHosts = count($this->data['hosts']);
-+
-+$js->addItem("<div id=\"counter\" 
style=\"font-size:20px;padding:5px;\">0/$numHosts</div>");
-+$js->addItem("<div id=\"content\"></div>");
-+$js->addItem("<script type=\"text/javascript\" 
src=\"js/jquery/jquery.js\"></script>");
-+$js->addItem("<script type=\"text/javascript\">");
-+$js->addItem("var hosts = new Array();");
-+$js->addItem("var ctr = 0;");
-+
-+for($i = 0; $i < $numHosts; $i++)
-+{
-+    $host = $this->data['hosts'][$i];
-+    $js->addItem("hosts[$i] = ".$host['hostid'].";");
-+}
-+
-+$sid = $this->data['sid'];
-+$scriptid = $this->data['scriptid'];
-+$js->addItem("for(var i=0;i<$numHosts;i++){
-+    $.ajax({
-+    url: 
\"scripts_exec.php?sid=$sid&execute=1&scriptid=$scriptid&strip=1&hostid=\"+hosts[i],
-+    async: true,
-+    success: function(data) { $('#content').append(data); ctr++; 
$('#counter').html(ctr+'/$numHosts') }
-+    });
-+}");
-+
-+
-+//$js->addItem();
-+$js->addItem("</script>");
-+
-+return $js;
-diff --git include/views/general.script.execute.php 
include/views/general.script.execute.php
-index 5f8d2f6..19eaec8 100644
---- include/views/general.script.execute.php
-+++ include/views/general.script.execute.php
-@@ -27,8 +27,17 @@ $scriptForm->setName('scriptForm');
- 
- // append tabs to form
- $scriptTab = new CTabView();
--$scriptTab->addTab('scriptTab', _s('Result of "%s"', 
$this->data['info']['name']), new CSpan($this->data['message'], 'pre 
fixedfont'));
-+$body = new CSpan($this->data['message'],'pre fixedfont');
-+if(isset($this->data['error']))
-+{
-+    $body = new CList(null, "messages");
-+    $body->addItem(new CListItem($this->data['error'], "error"));
-+}
-+
-+//    $scriptTab->addTab('errorTab', _s('ERROR'), new 
CSpan($this->data['error'], 'pre fixedfont'));
-+$scriptTab->addTab('scriptTab', _s('Result of "%s" ON 
'.$this->data['host']['name'], $this->data['info']['name']), $body);
- $scriptForm->addItem($scriptTab);
- 
- $scriptWidget->addItem($scriptForm);
-+$scriptWidget->addItem(BR());
- return $scriptWidget;
-diff --git js/main.js js/main.js
-index 4f14d4d..2bceabb 100644
---- js/main.js
-+++ js/main.js
-@@ -103,7 +103,7 @@ var PageRefresh = {
-  * Main menu
-  */
- var MMenu = {
--      menus:                  {'empty': 0, 'view': 0, 'cm': 0, 'reports': 0, 
'config': 0, 'admin': 0},
-+      menus:                  {'empty': 0, 'view': 0, 'cm': 0, 'reports': 0, 
'config': 0, 'admin': 0, 'experiment':0},
-       def_label:              null,
-       sub_active:     false,
-       timeout_reset:  null,
-diff --git manage_monitoring.php manage_monitoring.php
-new file mode 100644
-index 0000000..a01bbfa
---- /dev/null
-+++ manage_monitoring.php
-@@ -0,0 +1,61 @@
-+<?php
-+/*
-+** Zabbix
-+** Copyright (C) 2000-2011 Zabbix SIA
-+**
-+** This program is free software; you can redistribute it and/or modify
-+** it under the terms of the GNU General Public License as published by
-+** the Free Software Foundation; either version 2 of the License, or
-+** (at your option) any later version.
-+**
-+** This program is distributed in the hope that it will be useful,
-+** but WITHOUT ANY WARRANTY; without even the implied warranty of
-+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+** GNU General Public License for more details.
-+**
-+** You should have received a copy of the GNU General Public License
-+** along with this program; if not, write to the Free Software
-+** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
USA.
-+**/
-+
-+require_once 'include/config.inc.php';
-+require_once 'include/hosts.inc.php';
-+require_once 'include/items.inc.php';
-+require_once 'include/forms.inc.php';
-+
-+$page['title'] = _('Manage Monitoring');
-+$page['file'] = 'manage_monitoring.php';
-+
-+define('ZBX_PAGE_NO_MENU', 1);
-+
-+// VAR        TYPE    OPTIONAL        FLAGS   VALIDATION      EXCEPTION
-+$fields = array(
-+      'template'      =>      array(T_ZBX_INT,        O_OPT,  P_SYS,          
DB_ID,  true),
-+      'action'                =>      array(T_ZBX_STR,        O_OPT,  
NOT_EMPTY,      null,   true),
-+);
-+check_fields($fields);
-+
-+$templates = array_keys($_REQUEST['template']);
-+
-+//fetch template
-+$options = array(
-+      'templateids' => $templates,
-+      'selectItems' => array(),
-+      'output' => array('name')
-+);
-+$templates = API::Template()->get($options);
-+
-+//pull all item ids in array
-+$all_items = array();
-+foreach($templates as $temp)
-+{
-+      foreach($temp['items'] as $item)
-+              $all_items[] = $item['itemid'];
-+}
-+
-+//perform action
-+DBstart();
-+$go_result = ($_REQUEST['action'] == 
'disable')?disable_item($all_items):activate_item($all_items);
-+$go_result = DBend($go_result);
-+
-+jsRedirect('dashboard.php');
-diff --git results.php results.php
-new file mode 100644
-index 0000000..6cf8a87
---- /dev/null
-+++ results.php
-@@ -0,0 +1,101 @@
-+<?php
-+
-+require_once dirname(__FILE__).'/include/config.inc.php';
-+require_once dirname(__FILE__).'/include/experiments/inc.php';
-+
-+$page['title'] = _('Experiment Results');
-+$page['file'] = 'results.php';
-+$page['hist_arg'] = array('resid');
-+
-+require_once dirname(__FILE__).'/include/page_header.php';
-+
-+// VAR        TYPE    OPTIONAL        FLAGS   VALIDATION      EXCEPTION
-+$fields = array(
-+    'runid' =>   array(T_ZBX_INT, O_OPT, P_SYS|P_ACT, null, null),
-+    'hostid' =>   array(T_ZBX_INT, O_OPT, P_SYS|P_ACT, null, null),
-+    'delete' =>    array(T_ZBX_INT, O_OPT, P_SYS|P_ACT, null, null),
-+    'interrupt' =>    array(T_ZBX_INT, O_OPT, P_SYS|P_ACT, null, null),
-+    'rerun' =>    array(T_ZBX_INT, O_OPT, P_SYS|P_ACT, null, null)
-+);
-+check_fields($fields);
-+
-+/*
-+ * Actions
-+ */
-+
-+if(isset($_REQUEST['delete']))
-+{
-+    if(exprun_checkpermission($_REQUEST['delete']))
-+    {
-+        exprun_delete($_REQUEST['delete']);    
-+        jsRedirect('results.php');
-+    }
-+    else
-+        error("No permission to delete.");
-+}
-+
-+if(isset($_REQUEST['interrupt']))
-+{
-+    if(exprun_checkpermission($_REQUEST['interrupt']))
-+    {
-+        exprun_interrupt($_REQUEST['interrupt']);
-+        jsRedirect('results.php');
-+    }
-+    else
-+        error("No permission to interrupt.");
-+}
-+
-+if(isset($_REQUEST['rerun']))
-+{
-+    if(exprun_checkpermission($_REQUEST['rerun']))
-+    {
-+        exprun_rerun($_REQUEST['rerun']);
-+        jsRedirect('results.php');
-+    }
-+    else
-+        error("No permission to rerun.");
-+}
-+
-+/*
-+ * Display
-+ */
-+$resView = new CView('experiments.results');
-+
-+$results = exprun_getall(true);
-+$resView->set('results', $results);
-+
-+if(isset($_REQUEST['runid']))
-+{
-+    if(exprun_verifyid($_REQUEST['runid']))
-+    {
-+        foreach($results as $r) //get the specific run that we want to 
display the log for
-+        {
-+            if($r['runid'] == $_REQUEST['runid'])
-+            {
-+                $run = $r;
-+                break;
-+            }
-+        }
-+        
-+        $sep = 
"\n=================================================================\n";
-+        $log = '';
-+        foreach($run['nodes'] as $n)
-+        {
-+            if(isset($_REQUEST['hostid']) && $n['hostid'] == 
$_REQUEST['hostid']) //print the log of only a specific host
-+            {
-+                $log = $n['log'];
-+                break;
-+            }
-+            else
-+                $log .= $n['log'].$sep;
-+        }
-+        
-+        $resView->set('log', $log);
-+        $resView->set('runid', $run['runid']);
-+    }
-+}
-+
-+$resView->render();
-+$resView->show();
-+
-+require_once dirname(__FILE__).'/include/page_footer.php';
-diff --git scripts_exec.php scripts_exec.php
-index d40b5a0..94775ee 100644
---- scripts_exec.php
-+++ scripts_exec.php
-@@ -27,23 +27,28 @@ $page['file'] = 'scripts_exec.php';
- 
- define('ZBX_PAGE_NO_MENU', 1);
- 
--require_once ('include/page_header.php');
-+$strip = isset($_REQUEST['strip']);
-+if(!$strip)
-+    require_once ('include/page_header.php');
- 
- // VAR        TYPE    OPTIONAL        FLAGS   VALIDATION      EXCEPTION
- $fields = array(
--      'hostid' =>             array(T_ZBX_INT, O_OPT, P_SYS, DB_ID,           
'isset({execute})'),
-+      'hostid' =>             array(T_ZBX_INT, O_OPT, P_SYS, DB_ID,           
'!isset({groupid})&&!isset({hosts})'),
-       'scriptid' =>   array(T_ZBX_INT, O_OPT, P_SYS, DB_ID,           
'isset({execute})'),
-+      'groupid' =>    array(T_ZBX_INT, O_OPT, P_SYS, DB_ID,       
'!isset({hostid})&&!isset({hosts})'),
-+      'hosts' =>              array(T_ZBX_INT, O_OPT, P_SYS, DB_ID,       
'!isset({hostid})&&!isset({groupid})'),
-       'execute' =>    array(T_ZBX_INT, O_OPT, P_ACT, IN('0,1'),       null)
- );
- check_fields($fields);
- 
--if (isset($_REQUEST['execute'])) {
--      $scriptid = get_request('scriptid');
--      $hostid = get_request('hostid');
--
--      $data = array(
-+function execute_script($scriptid, $hostid)
-+{
-+    global $strip;
-+    
-+    $data = array(
-               'message' => '',
--              'info' => DBfetch(DBselect('SELECT s.name FROM scripts s WHERE 
s.scriptid='.$scriptid))
-+              'info' => DBfetch(DBselect('SELECT s.name FROM scripts s WHERE 
s.scriptid='.$scriptid)),
-+              'host' => DBfetch(DBselect('SELECT h.name FROM hosts h WHERE 
h.hostid='.$hostid))
-       );
- 
-       $result = API::Script()->execute(array('hostid' => $hostid, 'scriptid' 
=> $scriptid));
-@@ -53,8 +58,10 @@ if (isset($_REQUEST['execute'])) {
-               $isErrorExist = true;
-       }
-       elseif ($result['response'] == 'failed') {
--              error($result['value']);
--              $isErrorExist = true;
-+          if($strip) $data['error'] = $result['value'];
-+              else
-+                  error($result['value']);
-+          $isErrorExist = true;
-       }
-       else {
-               $data['message'] = $result['value'];
-@@ -70,4 +77,46 @@ if (isset($_REQUEST['execute'])) {
-       $scriptView->show();
- }
- 
--require_once 'include/page_footer.php';
-+if (isset($_REQUEST['execute'])) {
-+      $scriptid = get_request('scriptid');
-+      
-+      if(isset($_REQUEST['groupid']) || isset($_REQUEST['hosts']))
-+      {
-+              if(isset($_REQUEST['groupid']))
-+              {
-+                      $groupid = get_request('groupid');
-+                      
-+                      $hosts = API::Host()->get(array(
-+                              'groupids' => array($groupid),
-+                              'editable' => 1,
-+                              'output' => API_OUTPUT_EXTEND
-+                      ));
-+              }
-+              else
-+              {
-+                      $hosts = API::Host()->get(array(
-+                              'hostids' => get_request('hosts'),
-+                              'editable' => 1,
-+                              'output' => API_OUTPUT_EXTEND
-+                      ));
-+              }
-+              
-+              $data = array();
-+              $data['hosts'] = $hosts;
-+              $data['scriptid'] = $scriptid;
-+              $data['sid'] = get_request('sid');
-+              
-+              $scriptView = new CView('general.script.execute-parallel', 
$data);
-+      $scriptView->render();
-+      $scriptView->show();
-+              
-+      }
-+      elseif(isset($_REQUEST['hostid']))
-+      {
-+          $hostid = get_request('hostid');
-+      execute_script($scriptid, $hostid);
-+      }
-+}
-+
-+if(!$strip)
-+    require_once 'include/page_footer.php';
-diff --git targets.php targets.php
-new file mode 100644
-index 0000000..0d5e121
---- /dev/null
-+++ targets.php
-@@ -0,0 +1,50 @@
-+<?php
-+
-+error_reporting(E_ALL & ~E_DEPRECATED & ~E_STRICT);
-+
-+require_once dirname(__FILE__).'/include/config.inc.php';
-+require_once dirname(__FILE__).'/include/experiments/inc.php';
-+
-+$page['title'] = _('Target Configuration');
-+$page['file'] = 'targets.php';
-+$page['hist_arg'] = array('targetid');
-+
-+require_once dirname(__FILE__).'/include/page_header.php';
-+
-+/*
-+ * Actions
-+ */
-+//print_r($_REQUEST);
-+
-+if(isset($_REQUEST['target']) && isset($_REQUEST['apply']))
-+{
-+    switch($_REQUEST['target'])
-+    {
-+        case 'ssh':
-+            if(isset($_REQUEST['sshhosts']))
-+                expssh_updatehosts($_REQUEST['sshhosts']);
-+        
-+            break;
-+        
-+        case 'planetlab':
-+            if(isset($_REQUEST['plnodes']) && is_array($_REQUEST['plnodes']))
-+                exppl_updateSliceNodes($_REQUEST['plnodes']);
-+            break;
-+    }
-+}
-+
-+/*
-+ * Display
-+ */
-+$targetsView = new CView('experiments.targets');
-+
-+$targetsView->set('targetlist', $exp_targetlist);
-+if(isset($_REQUEST['target'])) $targetsView->set('selected_target', 
$_REQUEST['target']);
-+$targetsView->set('sshhosts', expnodes_gethosts('ssh'));
-+if(isset($_REQUEST['ploffset'])) $targetsView->set('ploffset', 
$_REQUEST['ploffset']);
-+if(isset($_REQUEST['plfilter']) && trim($_REQUEST['plfilter']) != '') 
$targetsView->set('plfilter', $_REQUEST['plfilter']);
-+
-+$targetsView->render();
-+$targetsView->show();
-+
-+require_once dirname(__FILE__).'/include/page_footer.php';
-diff --git tasklist.php tasklist.php
-new file mode 100644
-index 0000000..fa43c0d
---- /dev/null
-+++ tasklist.php
-@@ -0,0 +1,104 @@
-+<?php
-+
-+require_once dirname(__FILE__).'/include/config.inc.php';
-+require_once dirname(__FILE__).'/include/experiments/inc.php';
-+
-+$page['title'] = _('Tasklists');
-+$page['file'] = 'tasklist.php';
-+$page['hist_arg'] = array('taskid');
-+
-+require_once dirname(__FILE__).'/include/page_header.php';
-+
-+// VAR        TYPE    OPTIONAL        FLAGS   VALIDATION      EXCEPTION
-+/*$fields = array(
-+      'tid' =>                array(T_ZBX_INT, O_OPT, P_SYS, null, null),
-+);
-+check_fields($fields);*/
-+
-+
-+/*
-+ * Actions
-+ */
-+if(isset($_REQUEST['tid']) && isset($_REQUEST['update']))
-+{
-+    $tid = intval($_REQUEST['tid']);
-+    if(exptasklist_allowed($tid) == 2) //check user permission (read/write)
-+        exptasklist_update($tid, $_REQUEST);
-+    else
-+        error("Permission denied!");
-+}
-+if(isset($_REQUEST['add']))
-+{
-+    if(exptasklist_add($_REQUEST))
-+        jsRedirect('tasklist.php');
-+}
-+if(isset($_REQUEST['delete']))
-+{
-+    $tid = intval(substr($_REQUEST['delete'], 1));
-+    
-+    if(exptasklist_allowed($tid) == 2)
-+    {
-+        if(exptasklist_delete($tid))
-+            jsRedirect('tasklist.php');
-+    }
-+    else
-+        error("Permission denied!");
-+}
-+
-+
-+/*
-+ * Display
-+ */
-+if(isset($_REQUEST['tid']))
-+{
-+    $tid = intval($_REQUEST['tid']);
-+    if(exptasklist_allowed($tid) > 0) //check user permission (read or 
read/write)
-+    {
-+        //Get tasklist metadata
-+        $meta = exptasklist_getbyid($tid);
-+        //Get tasklist XML content
-+        $xml = exptasklist_getcontent($tid);
-+        if($xml)
-+        {
-+            $tlView = new CView('experiments.tasklist.edit');
-+
-+            $tlView->set('tid', $tid);
-+            $tlView->set('xml', simplexml_load_string($xml));
-+            //$tlView->set('targets', exp_gettargets());
-+            $tlView->set('meta', $meta);
-+            $tlView->set('exptasklist_defaults', $exptasklist_defaults);
-+            $tlView->set('userfiles', expfiles_getuserfiles());
-+
-+            $tlView->render();
-+            $tlView->show();
-+
-+        }
-+        else
-+            error("Error while loading tasklist!");
-+    }
-+    else
-+        error("Permission denied!");
-+}
-+elseif(isset($_REQUEST['new']))
-+{
-+    $tlView = new CView('experiments.tasklist.edit');
-+    
-+    $tlView->set('new', true);
-+    //$tlView->set('targets', exp_gettargets());
-+    $tlView->set('exptasklist_defaults', $exptasklist_defaults);
-+    $tlView->set('userfiles', expfiles_getuserfiles());
-+    
-+    $tlView->render();
-+    $tlView->show();
-+}
-+else
-+{
-+    $tlView = new CView('experiments.tasklist');
-+    
-+    $tlView->set('tasklists', exptasklist_getall(true));
-+    
-+    $tlView->render();
-+    $tlView->show();
-+}
-+
-+require_once dirname(__FILE__).'/include/page_footer.php';

Deleted: eclectic/gplmt-ui/schema.sql
===================================================================
--- eclectic/gplmt-ui/schema.sql        2014-05-26 19:38:06 UTC (rev 33404)
+++ eclectic/gplmt-ui/schema.sql        2014-05-26 19:45:47 UTC (rev 33405)
@@ -1,139 +0,0 @@
--- phpMyAdmin SQL Dump
--- version 3.4.11.1deb2
--- http://www.phpmyadmin.net
---
--- Host: localhost
--- Generation Time: Sep 26, 2013 at 04:39 PM
--- Server version: 5.5.31
--- PHP Version: 5.4.4-14+deb7u4
-
-SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
-SET time_zone = "+00:00";
-
-
-/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
-/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
-/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
-/*!40101 SET NAMES utf8 */;
-
---
--- Database: `zabbix`
---
-
--- --------------------------------------------------------
-
---
--- Table structure for table `exp_config`
---
-
-CREATE TABLE IF NOT EXISTS `exp_config` (
-  `configid` int(11) NOT NULL AUTO_INCREMENT,
-  `section` varchar(100) COLLATE utf8_bin NOT NULL,
-  `name` varchar(200) COLLATE utf8_bin NOT NULL,
-  `label` varchar(100) COLLATE utf8_bin NOT NULL,
-  `description` text COLLATE utf8_bin,
-  `type` varchar(100) COLLATE utf8_bin NOT NULL,
-  `default_value` varchar(500) COLLATE utf8_bin NOT NULL,
-  `user_editable` tinyint(1) NOT NULL,
-  PRIMARY KEY (`configid`)
-) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=29 ;
-
--- --------------------------------------------------------
-
---
--- Table structure for table `exp_configenum`
---
-
-CREATE TABLE IF NOT EXISTS `exp_configenum` (
-  `id` int(11) NOT NULL AUTO_INCREMENT,
-  `configid` int(11) NOT NULL,
-  `label` text COLLATE utf8_bin NOT NULL,
-  `value` text COLLATE utf8_bin NOT NULL,
-  PRIMARY KEY (`id`)
-) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=3 ;
-
--- --------------------------------------------------------
-
---
--- Table structure for table `exp_host`
---
-
-CREATE TABLE IF NOT EXISTS `exp_host` (
-  `hostid` int(11) NOT NULL AUTO_INCREMENT,
-  `target` varchar(200) COLLATE utf8_bin NOT NULL,
-  `userid` int(11) NOT NULL,
-  `host` text COLLATE utf8_bin NOT NULL,
-  `pl_nodeid` int(11) DEFAULT NULL,
-  PRIMARY KEY (`hostid`,`target`)
-) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=1580 ;
-
--- --------------------------------------------------------
-
---
--- Table structure for table `exp_run`
---
-
-CREATE TABLE IF NOT EXISTS `exp_run` (
-  `runid` int(11) NOT NULL AUTO_INCREMENT,
-  `startedon` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
-  `usetasklist` tinyint(1) NOT NULL DEFAULT '1',
-  `tasklistid` int(11) DEFAULT NULL,
-  `command` varchar(200) COLLATE utf8_bin DEFAULT NULL,
-  `target` varchar(200) COLLATE utf8_bin NOT NULL,
-  `pid` int(11) DEFAULT NULL,
-  `userid` int(11) NOT NULL,
-  `status` int(11) NOT NULL DEFAULT '0',
-  `percentage` double NOT NULL DEFAULT '0',
-  `fullcommand` text COLLATE utf8_bin,
-  PRIMARY KEY (`runid`)
-) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=75 ;
-
--- --------------------------------------------------------
-
---
--- Table structure for table `exp_runnode`
---
-
-CREATE TABLE IF NOT EXISTS `exp_runnode` (
-  `runid` int(11) NOT NULL,
-  `hostid` int(11) NOT NULL,
-  `target` varchar(200) COLLATE utf8_bin NOT NULL,
-  `status` int(11) NOT NULL DEFAULT '0',
-  `percentage` double NOT NULL DEFAULT '0',
-  `log` text COLLATE utf8_bin NOT NULL,
-  PRIMARY KEY (`runid`,`hostid`,`target`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-
--- --------------------------------------------------------
-
---
--- Table structure for table `exp_tasklist`
---
-
-CREATE TABLE IF NOT EXISTS `exp_tasklist` (
-  `tasklistid` int(11) NOT NULL AUTO_INCREMENT,
-  `name` varchar(100) COLLATE utf8_bin NOT NULL,
-  `description` text COLLATE utf8_bin,
-  `fsname` varchar(100) COLLATE utf8_bin NOT NULL,
-  `userid` int(11) NOT NULL,
-  `shared` tinyint(1) NOT NULL,
-  PRIMARY KEY (`tasklistid`)
-) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COLLATE=utf8_bin AUTO_INCREMENT=24 ;
-
--- --------------------------------------------------------
-
---
--- Table structure for table `exp_userconfig`
---
-
-CREATE TABLE IF NOT EXISTS `exp_userconfig` (
-  `configid` int(11) NOT NULL,
-  `userid` int(11) NOT NULL,
-  `value` varchar(500) COLLATE utf8_bin NOT NULL,
-  `enabled` tinyint(1) NOT NULL,
-  PRIMARY KEY (`configid`,`userid`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-
-/*!40101 SET address@hidden */;
-/*!40101 SET address@hidden */;
-/*!40101 SET address@hidden */;

Modified: eclectic/installation-guide.pdf
===================================================================
(Binary files differ)

Modified: eclectic/installation-guide.tex
===================================================================
--- eclectic/installation-guide.tex     2014-05-26 19:38:06 UTC (rev 33404)
+++ eclectic/installation-guide.tex     2014-05-26 19:45:47 UTC (rev 33405)
@@ -58,54 +58,20 @@
 \end{lstlisting}
 
 \chapter{Installing Zabbix Server}
-For our installation we used Zabbix in version 2.0.4 but our approach is 
supposed to work with newer version from the 2.x branch. An extensive Zabbix 
installation guide can be found on the Zabbix website:
-\href{https://www.zabbix.com/wiki/howto/install/ubuntu/ubuntuinstall}{Installing
 Zabbix on Ubuntu from source files}.
-To install Zabbix on the server the following steps are required:\\\\
-- Install required dependencies:
-\begin{lstlisting}
-sudo apt-get install build-essential mysql-server libmysqlclient15-dev php5 
php5-gd php5-mysql snmp libsnmp-dev snmpd libcurl4-openssl-dev fping libssh2-1 
libssh2-1-dev
-\end{lstlisting}
-- Download the Zabbix 2.0.4 source:
-\begin{lstlisting}
-$ wget 
http://sourceforge.net/projects/zabbix/files/ZABBIX%20Latest%20Stable/2.0.4/zabbix-2.0.4.tar.gz
-\end{lstlisting}
-- Unpack the archive file, compile and install Zabbix:
-\begin{lstlisting}
-$ tar xf zabbix-2.0.4.tar.gz
-$ cd zabbix-2.0.4
-$ ./configure --prefix=/home/experimentation/zabbix --enable-server 
--with-mysql --with-net-snmp --with-libcurl --with-ssh2
-$ make install
-\end{lstlisting}
-At this point, it is preferred to create a mysql account specifically for 
Zabbix.\\
-Replace <username> and <password> in the next section with the mysql 
credentials.\\
-- Setup Zabbix database:
-\begin{lstlisting}
-$ mysql -u<username> -p<password>
-mysql> create database zabbix character set utf8 collate utf8_bin;
-mysql> quit;
-$ mysql -u<username> -p<password> zabbix < database/mysql/schema.sql
-$ mysql -u<username> -p<password> zabbix < database/mysql/images.sql
-$ mysql -u<username> -p<password> zabbix < database/mysql/data.sql
-$ editor /home/experimentation/zabbix/etc/zabbix_server.conf
-\end{lstlisting}
-Change `LogFile`, `DBUser` and `DBPassword` accordingly.\\
-- Start Zabbix server:
-\begin{lstlisting}
-$ /home/experimentation/zabbix/sbin/zabbix_server start
-\end{lstlisting}
-- Setup Zabbix web frontend:
-\begin{lstlisting}
-$ sudo cp -r frontends/php/ /var/www/zabbix/
-$ sudo chown -R www-data:www-data /var/www/zabbix/
-\end{lstlisting}
-- Go to http://<server>/zabbix/ and follow the installation instructions 
shown.\\
-- If you need to change some PHP variables, locate your php.ini file, most 
likely in /etc/php5/apache2/php.ini, change the required variables then restart 
apache.\\
-- At this point, you can login through the web interface with the default 
admin credentials: Admin/zabbix
 
+Eclectic supports both Zabbix 2.0 and Zabbix 2.2.
 
+To install Zabbix 2.0:
+\href{https://www.zabbix.com/documentation/2.0/manual/installation}{https://www.zabbix.com/documentation/2.0/manual/installation}
+
+To install Zabbix 2.2:
+\href{https://www.zabbix.com/documentation/2.2/manual/installation}{https://www.zabbix.com/documentation/2.2/manual/installation}
+
+To upgrade from Zabbix 2.0 to Zabbix 2.2:
+\href{https://www.zabbix.com/documentation/2.2/manual/installation/upgrade}{https://www.zabbix.com/documentation/2.2/manual/installation/upgrade}
+
 \section{Installing GPLMT}
 
-
 This chapter covers the installation of \gplmt on a UNIX-style system. The 
steps described here should work for most recent distributions. Installation on 
Microsoft Windows Systems is not covered here.
 
 \subsection{Requirements}
@@ -182,7 +148,7 @@
 paramiko SSH module is required for execution, please check README
 \end{lstlisting}
 
-\section{Installing GPLMT GUI}
+\section{Installing GPLMT GUI (Zabbix 2.0)}
 
 \subsection{Requirements}
 
@@ -210,6 +176,45 @@
 \end{lstlisting}
 Change the value of \$GLOBALS['GPLMT\_DIR'] to the path you installed GPLMT to.
 
+\section{Installing GPLMT GUI (Zabbix 2.2)}
+
+\subsection{Requirements}
+
+\subsubsection{Pear XML\_RPC2}
+
+Installation:
+\begin{lstlisting}
+$ sudo apt-get install php-pear
+$ sudo pear install XML_RPC2
+\end{lstlisting}
+
+\subsubsection{MySql UDF SYS}
+
+Installation:
+\begin{lstlisting}
+$ git clone https://github.com/otarabai/lib_mysqludf_sys.git
+$ cd lib_mysqludf_sys
+$ sudo ./install.sh
+$ sudo adduser mysql www-data
+$ sudo /etc/init.d/mysql restart
+\end{lstlisting}
+
+\subsection{Installation}
+
+Assuming Zabbix has been installed as per the instructions above, GPLMT GUI 
can be installed by running the following:
+\begin{lstlisting}
+$ cd
+$ sudo chqrp -R www-data gplmt/ #replace gplmt/ with your GMPLT installation 
directory
+$ svn co https://gnunet.org/svn/eclectic/gplmt-ui/Zabbix-2.2
+$ cd Zabbix-2.2
+$ mysql -u<username> -p<password> zabbix < schema.sql # Replace <username> and 
<password>
+$ mysql -u<username> -p<password> zabbix < data.sql
+$ cd /var/www/zabbix/ # Or the zabbix web frontend directory if chosen 
differently
+$ sudo -u www-data patch -p0 < ~/Zabbix-2.2/patch.diff
+$ sudo -u www-data editor include/experiments/conf.php
+\end{lstlisting}
+Change the value of \$GLOBALS['GPLMT\_DIR'] to the path you installed GPLMT to.
+
 \section{Installing MSH}
 MSH depends on GNUnet's networking API and hence requires gnunet-0.9.5a to be
 installed.  Additionally, it requires an MPI implementation to be installed




reply via email to

[Prev in Thread] Current Thread [Next in Thread]