diff --git a/application/cmdbabstract.class.inc.php b/application/cmdbabstract.class.inc.php
index dc6d31b89..f8407dbca 100644
--- a/application/cmdbabstract.class.inc.php
+++ b/application/cmdbabstract.class.inc.php
@@ -4222,6 +4222,7 @@ EOF
$oDummyObj->Set($sAttCode, $currValue);
/** @var ormTagSet $oTagSet */
$oTagSet = $oDummyObj->Get($sAttCode);
+ $oTagSet->SetDisplayPartial(true);
foreach($aKeys as $iIndex => $sValues)
{
if ($iIndex == 0)
diff --git a/core/attributedef.class.inc.php b/core/attributedef.class.inc.php
index 4193c6e9f..2ae9aa44d 100644
--- a/core/attributedef.class.inc.php
+++ b/core/attributedef.class.inc.php
@@ -9668,14 +9668,27 @@ class AttributeTagSet extends AttributeSet
{
$aJson['partial_values'] = array();
$aJson['orig_value'] = array();
+ $aJson['added'] = array();
+ $aJson['removed'] = array();
}
else
{
- $aJson['partial_values'] = $oValue->GetModified();
$aJson['orig_value'] = array_merge($oValue->GetValues(), $oValue->GetModified());
+ $aJson['added'] = $oValue->GetAdded();
+ $aJson['removed'] = $oValue->GetRemoved();
+
+ if ($oValue->DisplayPartial())
+ {
+ // For bulk updates
+ $aJson['partial_values'] = $oValue->GetModified();
+ }
+ else
+ {
+ // For simple updates
+ $aJson['partial_values'] = array();
+ }
}
- $aJson['added'] = array();
- $aJson['removed'] = array();
+
$iMaxTags = $this->GetMaxItems();
$aJson['max_items_allowed'] = $iMaxTags;
diff --git a/core/dbobject.class.php b/core/dbobject.class.php
index 71498c920..412b959a9 100644
--- a/core/dbobject.class.php
+++ b/core/dbobject.class.php
@@ -1224,6 +1224,10 @@ abstract class DBObject implements iDisplay
if ($this->InSyncScope())
{
$iSynchroFlags = $this->GetSynchroReplicaFlags($sAttCode, $aReasons);
+ if ($iSynchroFlags & OPT_ATT_SLAVE)
+ {
+ $iSynchroFlags |= OPT_ATT_READONLY;
+ }
}
return $iFlags | $iSynchroFlags; // Combine both sets of flags
}
@@ -3869,7 +3873,7 @@ abstract class DBObject implements iDisplay
foreach(MetaModel::ListAttributeDefs($sLinkClass) as $sAttCode => $oAttDef)
{
// As of now, ignore other attribute (do not attempt to recurse!)
- if ($oAttDef->IsScalar())
+ if ($oAttDef->IsScalar() && $oAttDef->IsWritable())
{
$oLinkClone->Set($sAttCode, $oSourceLink->Get($sAttCode));
}
@@ -3932,7 +3936,7 @@ abstract class DBObject implements iDisplay
$oObjectToRead = $aSourceObjects['source'];
foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sAttCode => $oAttDef)
{
- if ($oAttDef->IsScalar())
+ if ($oAttDef->IsScalar() && $oAttDef->IsWritable())
{
$this->CopyAttribute($oObjectToRead, $sAttCode, $sAttCode);
}
diff --git a/core/expressioncache.class.inc.php b/core/expressioncache.class.inc.php
index 7d4161a13..eea5b79ce 100644
--- a/core/expressioncache.class.inc.php
+++ b/core/expressioncache.class.inc.php
@@ -77,11 +77,9 @@ EOF;
}
EOF;
- file_put_contents($sFilePath, $content);
- }
+ SetupUtils::builddir(dirname($sFilePath));
+ file_put_contents($sFilePath, $content);
}
- // Restore original user language
- Dict::SetUserLanguage($sUserLang);
}
static private function GetSerializedExpression($sClass, $sAttCode)
diff --git a/core/ormtagset.class.inc.php b/core/ormtagset.class.inc.php
index 46dc7e04f..b8f9a1481 100644
--- a/core/ormtagset.class.inc.php
+++ b/core/ormtagset.class.inc.php
@@ -26,6 +26,9 @@
*/
final class ormTagSet extends ormSet
{
+ private $m_bDisplayPartial = false;
+
+
/**
* ormTagSet constructor.
*
@@ -299,6 +302,82 @@ final class ormTagSet extends ormSet
return $aModifiedTagCodes;
}
+ /**
+ * @return string[] list of codes for added entries
+ */
+ public function GetAdded()
+ {
+ $aAddedTagCodes = array_keys($this->aAdded);
+ sort($aAddedTagCodes);
+
+ return $aAddedTagCodes;
+ }
+
+ /**
+ * @return string[] list of codes for removed entries
+ */
+ public function GetRemoved()
+ {
+ $aRemovedTagCodes = array_keys($this->aRemoved);
+ sort($aRemovedTagCodes);
+
+ return $aRemovedTagCodes;
+ }
+
+ /**
+ * Apply a delta to the current ItemSet
+ * $aDelta['added] = array of added items
+ * $aDelta['removed'] = array of removed items
+ *
+ * @param $aDelta
+ *
+ * @throws \CoreException
+ */
+ public function ApplyDelta($aDelta)
+ {
+ if (isset($aDelta['removed']))
+ {
+ foreach($aDelta['removed'] as $oItem)
+ {
+ $this->Remove($oItem);
+ }
+ }
+ if (isset($aDelta['added']))
+ {
+ foreach($aDelta['added'] as $oItem)
+ {
+ $this->Add($oItem);
+ }
+ }
+ }
+
+ /**
+ * Populates the added and removed arrays for bulk edit
+ *
+ * @param string[] $aItems
+ *
+ * @throws \CoreException
+ */
+ public function GenerateDiffFromArray($aItems)
+ {
+ foreach($this->GetValues() as $oCurrentItem)
+ {
+ if (!in_array($oCurrentItem, $aItems))
+ {
+ $this->Remove($oCurrentItem);
+ }
+ }
+
+ foreach($aItems as $oNewItem)
+ {
+ $this->Add($oNewItem);
+ }
+
+ // Keep only the aModified list
+ $this->aRemoved = array();
+ $this->aAdded = array();
+ }
+
/**
* Check whether a tag code is valid or not for this TagSet
*
@@ -479,4 +558,21 @@ final class ormTagSet extends ormSet
return TagSetFieldData::GetTagDataClassName($this->sClass, $this->sAttCode);
}
+
+ /**
+ * @return bool
+ */
+ public function DisplayPartial()
+ {
+ return $this->m_bDisplayPartial;
+ }
+
+ /**
+ * @param bool $m_bDisplayPartial
+ */
+ public function SetDisplayPartial($m_bDisplayPartial)
+ {
+ $this->m_bDisplayPartial = $m_bDisplayPartial;
+ }
+
}
\ No newline at end of file
diff --git a/datamodels/2.x/itop-backup/main.itop-backup.php b/datamodels/2.x/itop-backup/main.itop-backup.php
index 44029672c..ed0a93b83 100644
--- a/datamodels/2.x/itop-backup/main.itop-backup.php
+++ b/datamodels/2.x/itop-backup/main.itop-backup.php
@@ -47,31 +47,14 @@ class DBBackupScheduled extends DBBackup
{
protected function LogInfo($sMsg)
{
- static $bDebug = null;
- if ($bDebug == null)
- {
- $bDebug = MetaModel::GetConfig()->GetModuleSetting('itop-backup', 'debug', false);
- }
-
- if ($bDebug)
- {
- echo $sMsg."\n";
- }
+ echo $sMsg."\n";
+ IssueLog::Info($sMsg);
}
protected function LogError($sMsg)
{
- static $bDebug = null;
- if ($bDebug == null)
- {
- $bDebug = MetaModel::GetConfig()->GetModuleSetting('itop-backup', 'debug', false);
- }
-
IssueLog::Error($sMsg);
- if ($bDebug)
- {
- echo 'Error: '.$sMsg."\n";
- }
+ echo 'Error: '.$sMsg."\n";
}
/**
diff --git a/datamodels/2.x/itop-backup/module.itop-backup.php b/datamodels/2.x/itop-backup/module.itop-backup.php
index 9a43a3b16..e0db89476 100644
--- a/datamodels/2.x/itop-backup/module.itop-backup.php
+++ b/datamodels/2.x/itop-backup/module.itop-backup.php
@@ -52,7 +52,7 @@ SetupWebPage::AddModule(
//'file_name_format' => '__DB__-%Y-%m-%d_%H_%M',
'retention_count' => 5,
'enabled' => true,
- 'debug' => false,
+ 'itop_root' => '',
'itop_backup_incident' => '',
),
)
diff --git a/datamodels/2.x/itop-change-mgmt-itil/datamodel.itop-change-mgmt-itil.xml b/datamodels/2.x/itop-change-mgmt-itil/datamodel.itop-change-mgmt-itil.xml
index 622756a15..4b765f69c 100755
--- a/datamodels/2.x/itop-change-mgmt-itil/datamodel.itop-change-mgmt-itil.xml
+++ b/datamodels/2.x/itop-change-mgmt-itil/datamodel.itop-change-mgmt-itil.xml
@@ -4561,7 +4561,7 @@
itop-change-mgmt-itil/images/change-ongoing.png
-
- id) AND (DATE_ADD(C.end_date, INTERVAL 3 DAY) < NOW())]]>
+ id) AND (C.end_date < NOW() AND C.end_date > DATE_SUB(NOW(), INTERVAL 3 DAY ))]]>
Tickets:Related:RecentChanges
itop-change-mgmt-itil/images/change-done.png
@@ -4579,7 +4579,7 @@
itop-change-mgmt-itil/images/change-ongoing.png
-
- id) AND (DATE_ADD(C.end_date, INTERVAL 3 DAY) < NOW())]]>
+ id) AND (C.end_date < NOW() AND C.end_date > DATE_SUB(NOW(), INTERVAL 3 DAY ))]]>
Tickets:Related:RecentChanges
itop-change-mgmt-itil/images/change-done.png
@@ -4597,7 +4597,7 @@
itop-change-mgmt-itil/images/change-ongoing.png
-
- id) AND (DATE_ADD(C.end_date, INTERVAL 3 DAY) < NOW())]]>
+ id) AND (C.end_date < NOW() AND C.end_date > DATE_SUB(NOW(), INTERVAL 3 DAY ))]]>
Tickets:Related:RecentChanges
itop-change-mgmt-itil/images/change-done.png
@@ -4619,7 +4619,7 @@
itop-change-mgmt-itil/images/change-ongoing.png
-
-
+ DATE_SUB(NOW(), INTERVAL 3 DAY ))]]>
Tickets:Related:RecentChanges
itop-change-mgmt-itil/images/change-done.png
@@ -4633,7 +4633,7 @@
itop-change-mgmt-itil/images/change-ongoing.png
-
-
+ DATE_SUB(NOW(), INTERVAL 3 DAY ))]]>
Tickets:Related:RecentChanges
itop-change-mgmt-itil/images/change-done.png
diff --git a/dictionaries/en.dictionary.itop.ui.php b/dictionaries/en.dictionary.itop.ui.php
index dd811c5d8..f28d0c3e0 100644
--- a/dictionaries/en.dictionary.itop.ui.php
+++ b/dictionaries/en.dictionary.itop.ui.php
@@ -775,7 +775,7 @@ Dict::Add('EN US', 'English', 'English', array(
'UI:Title:DeletionOf_Object' => 'Deletion of %1$s',
'UI:Title:BulkDeletionOf_Count_ObjectsOf_Class' => 'Bulk deletion of %1$d objects of class %2$s',
'UI:Delete:NotAllowedToDelete' => 'You are not allowed to delete this object',
- 'UI:Delete:NotAllowedToUpdate_Fields' => 'You are not allowed to update the following field(s): %1$s',
+ 'UI:Error:ActionNotAllowed' => 'You are not allowed to do this action',
'UI:Error:NotEnoughRightsToDelete' => 'This object could not be deleted because the current user do not have sufficient rights',
'UI:Error:CannotDeleteBecause' => 'This object could not be deleted because: %1$s',
'UI:Error:CannotDeleteBecauseOfDepencies' => 'This object could not be deleted because some manual operations must be performed prior to that',
diff --git a/dictionaries/fr.dictionary.itop.ui.php b/dictionaries/fr.dictionary.itop.ui.php
index 3d4c86cdc..49acc5b77 100644
--- a/dictionaries/fr.dictionary.itop.ui.php
+++ b/dictionaries/fr.dictionary.itop.ui.php
@@ -758,6 +758,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
'UI:Title:BulkDeletionOf_Count_ObjectsOf_Class' => 'Suppression massive de %1$d objets de type %2$s',
'UI:Delete:NotAllowedToDelete' => 'Vous n\'êtes pas autorisé à supprimer cet objet',
'UI:Delete:NotAllowedToUpdate_Fields' => 'Vous n\'êtes pas autorisé à mettre à jour les champs suivants : %1$s',
+ 'UI:Error:ActionNotAllowed' => 'Vous n\'êtes pas autorisé à effectuer cette action',
'UI:Error:NotEnoughRightsToDelete' => 'Cet objet ne peut pas être supprimé car l\'utilisateur courant n\'a pas les droits nécessaires.',
'UI:Error:CannotDeleteBecause' => 'Cet objet ne peut pas être effacé. Raison: %1$s',
'UI:Error:CannotDeleteBecauseOfDepencies' => 'Cet objet ne peut pas être supprimé, des opérations manuelles sont nécessaire avant sa suppression.',
diff --git a/lib/archivetar/tar.php b/lib/archivetar/tar.php
index 050c22cfa..9337f7d57 100644
--- a/lib/archivetar/tar.php
+++ b/lib/archivetar/tar.php
@@ -1218,7 +1218,7 @@ class ArchiveTar
$iBufferLen = strlen("$v_buffer");
if ($iBufferLen != $iLen)
{
- $iPack = ((int)($iBufferLen / 512) + 1) * 512;
+ $iPack = (ceil($iBufferLen / 512)) * 512;
$sPack = sprintf('a%d', $iPack);
}
else
diff --git a/pages/UI.php b/pages/UI.php
index 3fcc41c10..4568aee3b 100644
--- a/pages/UI.php
+++ b/pages/UI.php
@@ -1497,7 +1497,15 @@ EOF
{
throw new ApplicationException(Dict::Format('UI:Error:3ParametersMissing', 'class', 'id', 'stimulus'));
}
- $oObj = MetaModel::GetObject($sClass, $id, false);
+ $aStimuli = MetaModel::EnumStimuli($sClass);
+ if ((get_class($aStimuli[$sStimulus]) !== 'StimulusUserAction') || (UserRights::IsStimulusAllowed($sClass, $sStimulus) === UR_ALLOWED_NO))
+ {
+ $sUser = UserRights::GetUser();
+ IssueLog::Error("UI.php '$operation' : Stimulus '$sStimulus' not allowed ! data: user='$sUser', class='$sClass'");
+ throw new ApplicationException(Dict::S('UI:Error:ActionNotAllowed'));
+ }
+
+ $oObj = MetaModel::GetObject($sClass, $id, false);
if ($oObj != null)
{
$aPrefillFormParam = array( 'user' => $_SESSION["auth_user"],
@@ -1545,6 +1553,13 @@ EOF
$sMessage = Dict::S('UI:Error:ObjectAlreadyUpdated');
$sSeverity = 'info';
}
+ elseif ((get_class($aStimuli[$sStimulus]) !== 'StimulusUserAction') || (UserRights::IsStimulusAllowed($sClass, $sStimulus) === UR_ALLOWED_NO))
+ {
+ $sUser = UserRights::GetUser();
+ IssueLog::Error("UI.php '$operation' : Stimulus '$sStimulus' not allowed ! data: user='$sUser', class='$sClass'");
+ $sMessage = Dict::S('UI:Error:ActionNotAllowed');
+ $sSeverity = 'error';
+ }
else
{
$sActionLabel = $aStimuli[$sStimulus]->GetLabel();
diff --git a/setup/ajax.dataloader.php b/setup/ajax.dataloader.php
index 6dfbbd8a5..127873410 100644
--- a/setup/ajax.dataloader.php
+++ b/setup/ajax.dataloader.php
@@ -147,9 +147,11 @@ header("Expires: Fri, 17 Jul 1970 05:00:00 GMT"); // Date in the past
$sOperation = Utils::ReadParam('operation', '');
try
{
- if (is_file(utils::GetConfigFilePath()) && !is_writable(utils::GetConfigFilePath()))
+ $sAuthent = utils::ReadParam('authent', '', false, 'raw_data');
+ if (!file_exists(APPROOT.'data/setup/authent') || $sAuthent !== file_get_contents(APPROOT.'data/setup/authent'))
{
- throw new Exception('Setup operations are not allowed outside of the setup');
+ throw new SecurityException('Setup operations are not allowed outside of the setup');
+ SetupPage::log_error("Setup operations are not allowed outside of the setup");
}
switch($sOperation)
diff --git a/setup/backup.class.inc.php b/setup/backup.class.inc.php
index 1eeb0254b..43753e530 100644
--- a/setup/backup.class.inc.php
+++ b/setup/backup.class.inc.php
@@ -313,8 +313,11 @@ if (class_exists('ZipArchive')) // The setup must be able to start even if the "
$sTmpFolder = APPROOT.'data/tmp-backup-'.rand(10000, getrandmax());
$aFiles = $this->PrepareFilesToBackup($sSourceConfigFile, $sTmpFolder);
+ $sFilesList = var_export($aFiles, true);
+ $this->LogInfo("backup: adding to archive files '$sFilesList'");
$oArchive->createModify($aFiles, '', $sTmpFolder);
+ $this->LogInfo("backup: removing tmp folder '$sTmpFolder'");
SetupUtils::rrmdir($sTmpFolder);
}
@@ -334,6 +337,7 @@ if (class_exists('ZipArchive')) // The setup must be able to start even if the "
{
SetupUtils::rrmdir($sTmpFolder);
}
+ $this->LogInfo("backup: creating tmp dir '$sTmpFolder'");
@mkdir($sTmpFolder, 0777, true);
if (is_null($sSourceConfigFile))
{
@@ -342,6 +346,7 @@ if (class_exists('ZipArchive')) // The setup must be able to start even if the "
if (!empty($sSourceConfigFile))
{
$sFile = $sTmpFolder.'/config-itop.php';
+ $this->LogInfo("backup: adding resource '$sSourceConfigFile'");
copy($sSourceConfigFile, $sFile);
$aRet[] = $sFile;
}
@@ -350,6 +355,7 @@ if (class_exists('ZipArchive')) // The setup must be able to start even if the "
if (file_exists($sDeltaFile))
{
$sFile = $sTmpFolder.'/delta.xml';
+ $this->LogInfo("backup: adding resource '$sDeltaFile'");
copy($sDeltaFile, $sFile);
$aRet[] = $sFile;
}
@@ -358,6 +364,7 @@ if (class_exists('ZipArchive')) // The setup must be able to start even if the "
{
$sModules = utils::GetCurrentEnvironment().'-modules';
$sFile = $sTmpFolder.'/'.$sModules;
+ $this->LogInfo("backup: adding resource '$sExtraDir'");
SetupUtils::copydir($sExtraDir, $sFile);
$aRet[] = $sFile;
}
@@ -434,7 +441,7 @@ if (class_exists('ZipArchive')) // The setup must be able to start even if the "
$sCommandDisplay = "$sMySQLDump --opt --skip-lock-tables --default-character-set=".$sMysqldumpCharset." --add-drop-database --single-transaction --host=$sHost $sPortOption --user=xxxxx --password=xxxxx $sTlsOptions --result-file=$sTmpFileName $sDBName $sTables";
// Now run the command for real
- $this->LogInfo("Executing command: $sCommandDisplay");
+ $this->LogInfo("backup: generate data file with command: $sCommandDisplay");
$aOutput = array();
$iRetCode = 0;
exec($sCommand, $aOutput, $iRetCode);
diff --git a/setup/compiler.class.inc.php b/setup/compiler.class.inc.php
index 3f53f9bf1..0716386dc 100644
--- a/setup/compiler.class.inc.php
+++ b/setup/compiler.class.inc.php
@@ -333,8 +333,9 @@ EOF;
$aMenusToLoad[] = $sMenuId;
}
$aMenusToLoad = array_unique($aMenusToLoad);
- $aMenusForAll = array();
- $aMenusForAdmins = array();
+ $aMenuLinesForAll = array();
+ $aMenuLinesForAdmins = array();
+ $aAdminMenus = array();
foreach($aMenusToLoad as $sMenuId)
{
$oMenuNode = $aMenuNodes[$sMenuId];
@@ -365,25 +366,27 @@ EOF;
{
throw new Exception("Failed to process menu '$sMenuId', from '$sModuleRootDir': ".$e->getMessage());
}
- if ($oMenuNode->GetChildText('enable_admin_only') == '1')
+ $sParent = $oMenuNode->GetChildText('parent', null);
+ if (($oMenuNode->GetChildText('enable_admin_only') == '1') || isset($aAdminMenus[$sParent]))
{
- $aMenusForAdmins = array_merge($aMenusForAdmins, $aMenuLines);
+ $aMenuLinesForAdmins = array_merge($aMenuLinesForAdmins, $aMenuLines);
+ $aAdminMenus[$oMenuNode->getAttribute("id")] = true;
}
else
{
- $aMenusForAll = array_merge($aMenusForAll, $aMenuLines);
+ $aMenuLinesForAll = array_merge($aMenuLinesForAll, $aMenuLines);
}
}
$sIndent = "\t\t";
- foreach ($aMenusForAll as $sPHPLine)
+ foreach ($aMenuLinesForAll as $sPHPLine)
{
$sCompiledCode .= $sIndent.$sPHPLine."\n";
}
- if (count($aMenusForAdmins) > 0)
+ if (count($aMenuLinesForAdmins) > 0)
{
$sCompiledCode .= $sIndent."if (UserRights::IsAdministrator())\n";
$sCompiledCode .= $sIndent."{\n";
- foreach ($aMenusForAdmins as $sPHPLine)
+ foreach ($aMenuLinesForAdmins as $sPHPLine)
{
$sCompiledCode .= $sIndent."\t".$sPHPLine."\n";
}
diff --git a/setup/setup.js b/setup/setup.js
index 2474d0fa3..88a7cba8f 100644
--- a/setup/setup.js
+++ b/setup/setup.js
@@ -2,8 +2,9 @@ function WizardAsyncAction(sActionCode, oParams, OnErrorFunction)
{
var sStepClass = $('#_class').val();
var sStepState = $('#_state').val();
+ var sAuthent = $('#authent_token').val();
- var oMap = { operation: 'async_action', step_class: sStepClass, step_state: sStepState, code: sActionCode, params: oParams };
+ var oMap = { operation: 'async_action', step_class: sStepClass, step_state: sStepState, code: sActionCode, authent : sAuthent, params: oParams };
var ErrorFn = OnErrorFunction;
$(document).ajaxError(function(event, request, settings) {
diff --git a/setup/wizardsteps.class.inc.php b/setup/wizardsteps.class.inc.php
index 91631d78f..1e3798c9c 100644
--- a/setup/wizardsteps.class.inc.php
+++ b/setup/wizardsteps.class.inc.php
@@ -57,6 +57,13 @@ class WizStepWelcome extends WizardStep
public function ProcessParams($bMoveForward = true)
{
+ if (!file_exists(APPROOT.'data/setup'))
+ {
+ mkdir(APPROOT.'data/setup');
+ }
+ $sUID = hash('sha256', rand());
+ file_put_contents(APPROOT.'data/setup/authent', $sUID);
+ $this->oWizard->SetParameter('authent', $sUID);
return array('class' => 'WizStepInstallOrUpgrade', 'state' => '');
}
@@ -284,6 +291,8 @@ class WizStepInstallOrUpgrade extends WizardStep
$oPage->add('
');
$oPage->add($sMySQLDumpMessage.' '.$sMessage.' |
');
$oPage->add('');
+ $sAuthentToken = $this->oWizard->GetParameter('authent', '');
+ $oPage->add('');
//$oPage->add('');
$oPage->add_ready_script(
<<add('');
SetupUtils::DisplayDBParameters($oPage, true, $sDBServer, $sDBUser, $sDBPwd, $sDBName, $sDBPrefix, $sTlsEnabled,
$sTlsCA, $sNewDBName);
+ $sAuthentToken = $this->oWizard->GetParameter('authent', '');
+ $oPage->add('');
$oPage->add('
');
$sCreateDB = $this->oWizard->GetParameter('create_db', 'yes');
if ($sCreateDB == 'no')
@@ -996,6 +1007,8 @@ class WizStepMiscParams extends WizardStep
$sChecked = ($sSampleData == 'no') ? 'checked ' : '';
$oPage->p('