diff --git a/application/application.inc.php b/application/application.inc.php index c04e8d679b..1a8b3f7627 100644 --- a/application/application.inc.php +++ b/application/application.inc.php @@ -16,5 +16,5 @@ require_once(APPROOT.'/application/audit.category.class.inc.php'); require_once(APPROOT.'/application/audit.domain.class.inc.php'); require_once(APPROOT.'/application/audit.rule.class.inc.php'); require_once(APPROOT.'/application/query.class.inc.php'); -require_once(APPROOT.'/setup/moduleinstallation.class.inc.php'); +require_once(APPROOT.'/setup/moduleinstallation/moduleinstallation.class.inc.php'); require_once(APPROOT.'/application/utils.inc.php'); diff --git a/application/dashboard.class.inc.php b/application/dashboard.class.inc.php index a7ded14dad..e477f66c76 100644 --- a/application/dashboard.class.inc.php +++ b/application/dashboard.class.inc.php @@ -497,7 +497,7 @@ EOF * @param array $aExtraParams * @param bool $bCanEdit * - * @return \Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardLayout + * @return null|\Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardLayout */ public function Render($oPage, $bEditMode = false, $aExtraParams = [], $bCanEdit = true) { diff --git a/application/exceptions/CoreException.php b/application/exceptions/CoreException.php index 6751665aa2..eba5616f3a 100644 --- a/application/exceptions/CoreException.php +++ b/application/exceptions/CoreException.php @@ -14,6 +14,8 @@ class CoreException extends Exception /** * CoreException constructor. * + * ATTENTION: Logging here will break the CI + * * @param string $sIssue error message * @param array|null $aContextData key/value array, value MUST implements _toString * @param string $sImpact diff --git a/application/forms.class.inc.php b/application/forms.class.inc.php index d1fd70fc8a..61f62ded64 100644 --- a/application/forms.class.inc.php +++ b/application/forms.class.inc.php @@ -1387,7 +1387,7 @@ class DesignerIconSelectionField extends DesignerFormField public function AddAllowedValue($aValue) { // Add a null value to the list of allowed values - $this->aAllowedValues = array_merge([$aValue], $this->aAllowedValues); + $this->aAllowedValues = array_merge([$aValue], $this->aAllowedValues ?? [null]); } public function EnableUpload($sIconUploadUrl) { diff --git a/application/utils.inc.php b/application/utils.inc.php index 8caba53e6d..915319c71b 100644 --- a/application/utils.inc.php +++ b/application/utils.inc.php @@ -284,9 +284,7 @@ class utils } // Read and record the value for switching the archive mode $iCurrent = self::ReadParam('with-archive', $iDefault); - if (Session::IsInitialized()) { - Session::Set('archive_mode', $iCurrent); - } + Session::Set('archive_mode', $iCurrent); // Read and use the value for the current page (web services) $iCurrent = self::ReadParam('with_archive', $iCurrent, true); self::$bPageMode = ($iCurrent == 1); @@ -976,7 +974,7 @@ class utils return self::$oConfig; } - $sProductionEnvConfigPath = self::GetConfigFilePath('production'); + $sProductionEnvConfigPath = self::GetConfigFilePath(ITOP_DEFAULT_ENV); if (file_exists($sProductionEnvConfigPath)) { $oProductionEnvDiskConfig = new Config($sProductionEnvConfigPath); self::SetConfig($oProductionEnvDiskConfig); @@ -3192,4 +3190,30 @@ TXT } } } + + /** + * Read memory limit from the php.ini file + * + * @return int Memory limit in bytes + */ + public static function GetMemoryLimit(): int + { + $sLimit = ini_get('memory_limit'); + if ($sLimit == '-1') { + return 128 * 1048576; + } + switch (substr($sLimit, -1)) { + case 'M': + case 'm': + return (int)$sLimit * 1048576; + case 'K': + case 'k': + return (int)$sLimit * 1024; + case 'G': + case 'g': + return (int)$sLimit * 1073741824; + default: + return (int)$sLimit; + } + } } diff --git a/core/autoload.php b/core/autoload.php index 83f4e972cb..b244272b86 100644 --- a/core/autoload.php +++ b/core/autoload.php @@ -24,7 +24,7 @@ MetaModel::IncludeModule('application/user.dashboard.class.inc.php'); MetaModel::IncludeModule('application/audit.rule.class.inc.php'); MetaModel::IncludeModule('application/audit.domain.class.inc.php'); MetaModel::IncludeModule('application/query.class.inc.php'); -MetaModel::IncludeModule('setup/moduleinstallation.class.inc.php'); +MetaModel::IncludeModule('setup/moduleinstallation/moduleinstallation.class.inc.php'); MetaModel::IncludeModule('core/event.class.inc.php'); MetaModel::IncludeModule('core/action.class.inc.php'); diff --git a/core/config.class.inc.php b/core/config.class.inc.php index 0ee78f8a76..fae11cc153 100644 --- a/core/config.class.inc.php +++ b/core/config.class.inc.php @@ -20,9 +20,6 @@ * */ -use Combodo\iTop\Config\Validator\iTopConfigAstValidator; -use Combodo\iTop\Config\Validator\iTopConfigSyntaxValidator; - define('ITOP_APPLICATION', 'iTop'); define('ITOP_APPLICATION_SHORT', 'iTop'); @@ -1182,8 +1179,8 @@ class Config 'tracking_level_linked_set_default' => [ 'type' => 'integer', 'description' => 'Default tracking level if not explicitly set at the attribute level, for AttributeLinkedSet (defaults to NONE in case of a fresh install, LIST otherwise - this to preserve backward compatibility while upgrading from a version older than 2.0.3 - see TRAC #936)', - 'default' => LINKSET_TRACKING_LIST, - 'value' => LINKSET_TRACKING_LIST, + 'default' => LINKSET_TRACKING_NONE, + 'value' => LINKSET_TRACKING_NONE, 'source_of_value' => '', 'show_in_conf_sample' => false, ], @@ -2755,14 +2752,13 @@ class Config * * @param array $aParamValues * @param ?string $sModulesDir - * @param bool $bPreserveModuleSettings * * @return void The current object is modified directly * * @throws \Exception * @throws \CoreException */ - public function UpdateFromParams($aParamValues, $sModulesDir = null, $bPreserveModuleSettings = false) + public function UpdateFromParams($aParamValues, $sModulesDir = null) { if (isset($aParamValues['application_path'])) { $this->Set('app_root_url', $aParamValues['application_path']); @@ -2810,7 +2806,10 @@ class Config } else { $aSelectedModules = null; } - $this->UpdateIncludes($sModulesDir, $aSelectedModules); + + if (! is_null($sModulesDir)) { + $this->UpdateIncludes($sModulesDir, $aSelectedModules); + } if (isset($aParamValues['source_dir'])) { $this->Set('source_dir', $aParamValues['source_dir']); @@ -2828,17 +2827,13 @@ class Config * * @throws Exception */ - public function UpdateIncludes($sModulesDir, $aSelectedModules = null) + public function UpdateIncludes(string $sModulesDir, $aSelectedModules = null) { - if ($sModulesDir === null) { - return; - } - // Initialize the arrays below with default values for the application... $oEmptyConfig = new Config('dummy_file', false); // Do NOT load any config file, just set the default values $aAddOns = $oEmptyConfig->GetAddOns(); - $aModules = ModuleDiscovery::GetAvailableModules([APPROOT.$sModulesDir]); + $aModules = ModuleDiscovery::GetModulesOrderedByDependencies([APPROOT.$sModulesDir]); foreach ($aModules as $sModuleId => $aModuleInfo) { list($sModuleName, $sModuleVersion) = ModuleDiscovery::GetModuleName($sModuleId); if (is_null($aSelectedModules) || in_array($sModuleName, $aSelectedModules)) { diff --git a/core/dbobject.class.php b/core/dbobject.class.php index 9c82be25a2..38cc9d830e 100644 --- a/core/dbobject.class.php +++ b/core/dbobject.class.php @@ -5108,8 +5108,8 @@ abstract class DBObject implements iDisplay protected function GetReferencingObjectsForDeletion($bAllowAllData = false) { $aDependentObjects = []; - $aRererencingMe = MetaModel::EnumReferencingClasses(get_class($this)); - foreach ($aRererencingMe as $sRemoteClass => $aExtKeys) { + $aReferencingMe = MetaModel::EnumReferencingClasses(get_class($this)); + foreach ($aReferencingMe as $sRemoteClass => $aExtKeys) { /** @var \AttributeExternalKey $oExtKeyAttDef */ foreach ($aExtKeys as $sExtKeyAttCode => $oExtKeyAttDef) { // skip if external key doesn't require the deletion cascading diff --git a/core/designdocument.class.inc.php b/core/designdocument.class.inc.php index 65cd295b26..ca91d426fc 100644 --- a/core/designdocument.class.inc.php +++ b/core/designdocument.class.inc.php @@ -360,10 +360,10 @@ class DesignElement extends \DOMElement * @param string $sTagName * @param string|null $sDefault * - * @return string + * @return null|string * @throws \DOMFormatException */ - public function GetChildText($sTagName, $sDefault = null) + public function GetChildText($sTagName, $sDefault = null): ?string { $sRet = $sDefault; if ($oChild = $this->GetOptionalElement($sTagName)) { diff --git a/core/metamodel.class.php b/core/metamodel.class.php index 318fe37750..9fe20e3c6f 100644 --- a/core/metamodel.class.php +++ b/core/metamodel.class.php @@ -22,6 +22,8 @@ use Combodo\iTop\Application\EventRegister\ApplicationEvents; use Combodo\iTop\Core\MetaModel\FriendlyNameType; use Combodo\iTop\Service\Events\EventData; use Combodo\iTop\Service\Events\EventService; +use Combodo\iTop\Setup\ModuleDependency\Module; +use Combodo\iTop\Setup\ModuleDiscovery\ModuleFileReader; require_once APPROOT.'core/modulehandler.class.inc.php'; require_once APPROOT.'core/querymodifier.class.inc.php'; @@ -128,7 +130,7 @@ abstract class MetaModel /** @var array */ private static $m_aClassToFile = []; /** @var string */ - protected static $m_sEnvironment = 'production'; + protected static $m_sEnvironment = ITOP_DEFAULT_ENV; /** * Objects currently created/updated. @@ -462,6 +464,43 @@ abstract class MetaModel return call_user_func([$sClass, 'GetClassDescription'], $sClass); } + /** + * @param string $sClass + * + * @return string + * @throws \CoreException + */ + final public static function GetModuleName($sClass) + { + try { + $oReflectionClass = new ReflectionClass($sClass); + $sDir = realpath(dirname($oReflectionClass->getFileName())); + $sApproot = realpath(APPROOT); + while (($sDir !== $sApproot) && (str_contains($sDir, $sApproot))) { + $aFiles = glob("$sDir/module.*.php"); + if (count($aFiles) > 1) { + return 'core'; + } + + if (count($aFiles) == 0) { + $sDir = realpath(dirname($sDir)); + continue; + } + + $sModuleFilePath = $aFiles[0]; + $aModuleInfo = ModuleFileReader::GetInstance()->ReadModuleFileInformation($sModuleFilePath); + $sModuleId = $aModuleInfo[ModuleFileReader::MODULE_INFO_ID]; + list($sModuleName, ) = ModuleDiscovery::GetModuleName($sModuleId); + + return $sModuleName; + } + } catch (\Exception $e) { + throw new CoreException("Cannot find class module", ['class' => $sClass], '', $e); + } + + return 'core'; + } + /** * @param string $sClass * @@ -5709,7 +5748,7 @@ abstract class MetaModel * @throws \DictExceptionUnknownLanguage * @throws \Exception */ - public static function Startup($config, $bModelOnly = false, $bAllowCache = true, $bTraceSourceFiles = false, $sEnvironment = 'production') + public static function Startup($config, $bModelOnly = false, $bAllowCache = true, $bTraceSourceFiles = false, $sEnvironment = ITOP_DEFAULT_ENV) { // Startup on a new environment is not supported static $bStarted = false; diff --git a/core/ormtagset.class.inc.php b/core/ormtagset.class.inc.php index 1af6549052..ee5a25da9f 100644 --- a/core/ormtagset.class.inc.php +++ b/core/ormtagset.class.inc.php @@ -43,24 +43,24 @@ final class ormTagSet extends ormSet /** * - * @param array $aTagCodes + * @param array|null $aItems * * @throws \CoreException * @throws \CoreUnexpectedValue when a code is invalid */ - public function SetValues($aTagCodes) + public function SetValues($aItems) { - if (is_null($aTagCodes)) { - $aTagCodes = []; + if (is_null($aItems)) { + $aItems = []; } - if (!is_array($aTagCodes)) { - throw new CoreUnexpectedValue("Wrong value {$aTagCodes} for {$this->sClass}:{$this->sAttCode}"); + if (!is_array($aItems)) { + throw new CoreUnexpectedValue("Wrong value {$aItems} for {$this->sClass}:{$this->sAttCode}"); } $oTags = []; $iCount = 0; $bError = false; - foreach ($aTagCodes as $sTagCode) { + foreach ($aItems as $sTagCode) { $iCount++; if (($this->iLimit != 0) && ($iCount > $this->iLimit)) { $bError = true; diff --git a/css/backoffice/blocks-integrations/_all.scss b/css/backoffice/blocks-integrations/_all.scss index 4a5c31d678..c4315213d2 100644 --- a/css/backoffice/blocks-integrations/_all.scss +++ b/css/backoffice/blocks-integrations/_all.scss @@ -22,4 +22,6 @@ @import "medallion-with-blocklist"; @import "field-badge-within-datatable"; @import "jquery-blockui-within-dialog"; -@import "jquery-blockui-within-datatable"; \ No newline at end of file +@import "jquery-blockui-within-datatable"; +@import "badge-with-badge"; +@import "extension-details-with-extension-details"; \ No newline at end of file diff --git a/css/backoffice/blocks-integrations/_badge-with-badge.scss b/css/backoffice/blocks-integrations/_badge-with-badge.scss new file mode 100644 index 0000000000..6833ec9dce --- /dev/null +++ b/css/backoffice/blocks-integrations/_badge-with-badge.scss @@ -0,0 +1,10 @@ +/* + * @copyright Copyright (C) 2010-2026 Combodo SAS + * @license http://opensource.org/licenses/AGPL-3.0 + */ + +$ibo-badge--spacing-left--with-same-block: $ibo-spacing-200 !default; + +.ibo-badge + .ibo-badge { + margin-left: $ibo-badge--spacing-left--with-same-block; +} \ No newline at end of file diff --git a/css/backoffice/blocks-integrations/_extension-details-with-extension-details.scss b/css/backoffice/blocks-integrations/_extension-details-with-extension-details.scss new file mode 100644 index 0000000000..a59f4c36e1 --- /dev/null +++ b/css/backoffice/blocks-integrations/_extension-details-with-extension-details.scss @@ -0,0 +1,11 @@ +/* + * @copyright Copyright (C) 2010-2026 Combodo SAS + * @license http://opensource.org/licenses/AGPL-3.0 + */ + +$ibo-extension-details--margin-top: $ibo-spacing-300 !default; + +.ibo-extension-details + .ibo-extension-details, +.ibo-extension-details--information--description .ibo-extension-details { + margin-top: $ibo-extension-details--margin-top; +} diff --git a/css/backoffice/components/_all.scss b/css/backoffice/components/_all.scss index cb72f0880a..14e62bac21 100644 --- a/css/backoffice/components/_all.scss +++ b/css/backoffice/components/_all.scss @@ -33,4 +33,5 @@ @import "field-badge"; @import "file-select"; @import "medallion-icon"; -@import "toast"; \ No newline at end of file +@import "toast"; +@import "badge"; \ No newline at end of file diff --git a/css/backoffice/components/_badge.scss b/css/backoffice/components/_badge.scss new file mode 100644 index 0000000000..885fa1cb33 --- /dev/null +++ b/css/backoffice/components/_badge.scss @@ -0,0 +1,41 @@ +$ibo-badge--padding-x : $ibo-spacing-200 !default; +$ibo-badge--padding-y : $ibo-spacing-100 !default; +$ibo-badge--border-radius : $ibo-border-radius-400 !default; + +$ibo-badge-colors: ( + 'primary': ($ibo-color-primary-100, $ibo-color-primary-900), + 'secondary': ($ibo-color-secondary-100, $ibo-color-secondary-900), + 'neutral': ($ibo-color-secondary-100, $ibo-color-secondary-900), + 'information': ($ibo-color-information-100, $ibo-color-information-900), + 'success': ($ibo-color-success-100, $ibo-color-success-900), + 'failure': ($ibo-color-danger-100, $ibo-color-danger-900), + 'warning': ($ibo-color-warning-100,$ibo-color-warning-900), + 'danger': ($ibo-color-danger-100,$ibo-color-danger-900), + 'grey' : ($ibo-color-grey-100, $ibo-color-grey-900), + 'blue-grey': ($ibo-color-blue-grey-100, $ibo-color-blue-grey-900), + 'blue': ($ibo-color-blue-100, $ibo-color-blue-900), + 'cyan': ($ibo-color-cyan-100, $ibo-color-cyan-900), + 'green': ($ibo-color-green-100, $ibo-color-green-900), + 'orange' : ($ibo-color-orange-100, $ibo-color-orange-900), + 'red': ($ibo-color-red-100, $ibo-color-red-900), + 'pink': ($ibo-color-pink-100, $ibo-color-pink-900), +) !default; + + + +.ibo-badge { + display: inline-block; + white-space: nowrap; + padding : $ibo-badge--padding-y $ibo-badge--padding-x; + border-radius : $ibo-badge--border-radius; + @extend %ibo-font-ral-med-50; + + @each $sColor, $aColorValues in $ibo-badge-colors { + $bg-color: nth($aColorValues, 1); + $text-color: nth($aColorValues, 2); + &.ibo-is-#{$sColor} { + background-color: $bg-color; + color: $text-color; + } + } +} \ No newline at end of file diff --git a/css/backoffice/components/input/_input-toggler.scss b/css/backoffice/components/input/_input-toggler.scss index 90b11a49ad..333466198f 100644 --- a/css/backoffice/components/input/_input-toggler.scss +++ b/css/backoffice/components/input/_input-toggler.scss @@ -8,6 +8,7 @@ $ibo-toggler--wrapper--height: 20px !default; $ibo-toggler--slider--border-radius: $ibo-border-radius-900 !default; $ibo-toggler--slider--background-color: $ibo-color-secondary-600 !default; +$ibo-toggler--slider--disabled--background-color: $ibo-color-secondary-200 !default; $ibo-toggler--slider--before--left: 3px !default; $ibo-toggler--slider--before--bottom: 3px !default; @@ -17,6 +18,7 @@ $ibo-toggler--slider--before--border-radius: $ibo-border-radius-full !default; $ibo-toggler--slider--before--background-color: $ibo-color-grey-100 !default; $ibo-toggler--slider--checked--background-color: $ibo-color-primary-600 !default; +$ibo-toggler--slider--checked-disabled--background-color: $ibo-color-primary-200 !default; $ibo-toggler--slider--focus--box-shadow: 0 0 1px $ibo-color-primary-600 !default; $ibo-toggler--label--margin-left: 4px !default; @@ -61,6 +63,13 @@ $ibo-toggler--label--margin-left: 4px !default; background-color: $ibo-toggler--slider--checked--background-color; } +.ibo-toggler--wrapper input:disabled + .ibo-toggler--slider { + background-color: $ibo-toggler--slider--disabled--background-color; +} +.ibo-toggler--wrapper input:checked:disabled + .ibo-toggler--slider { + background-color: $ibo-toggler--slider--checked-disabled--background-color; +} + input:focus + .ibo-toggler--slider { box-shadow: $ibo-toggler--slider--focus--box-shadow; } diff --git a/css/backoffice/layout/_all.scss b/css/backoffice/layout/_all.scss index 584fa15c66..f1dabffb0c 100644 --- a/css/backoffice/layout/_all.scss +++ b/css/backoffice/layout/_all.scss @@ -15,3 +15,4 @@ @import "wizard-container/wizard-container"; @import "object/all"; @import "activity-panel/all"; +@import "extension/all"; \ No newline at end of file diff --git a/css/backoffice/layout/extension/_all.scss b/css/backoffice/layout/extension/_all.scss new file mode 100644 index 0000000000..1b423c913a --- /dev/null +++ b/css/backoffice/layout/extension/_all.scss @@ -0,0 +1 @@ +@import "extension-details"; diff --git a/css/backoffice/layout/extension/_extension-details.scss b/css/backoffice/layout/extension/_extension-details.scss new file mode 100644 index 0000000000..3fd5e51c92 --- /dev/null +++ b/css/backoffice/layout/extension/_extension-details.scss @@ -0,0 +1,76 @@ +$ibo-extension-details--information--metadata--padding: $ibo-spacing-200 !default; +$ibo-extension-details--information--metadata--delimiter: "-" !default; +$ibo-extension-details--information--metadata--color: $ibo-color-grey-700 !default; +$ibo-extension-details--actions--button--padding-y: 3px !default; +$ibo-extension-details--actions--button--padding-x: $ibo-button--padding-x !default; + +.ibo-extension-details { + display: inline-flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + width: 100%; +} + +.ibo-extension-details--information { + flex-grow: 1; + display: flex; + flex-direction: column; +} + +.ibo-extension-details--actions { + display: flex; +} + +.ibo-extension-details--information--label { + @extend %ibo-font-ral-med-150; +} + +.ibo-extension-details--information--metadata { + @extend %ibo-font-ral-med-100; + color: $ibo-extension-details--information--metadata--color; +} + +.ibo-extension-details--information--description { + @extend %ibo-font-ral-med-100; +} + +.ibo-extension-details--information--metadata span + span:before { + content: $ibo-extension-details--information--metadata--delimiter; + padding-left: $ibo-extension-details--information--metadata--padding; + padding-right: $ibo-extension-details--information--metadata--padding; +} + +//ibo-extension-details can have other ibo-extension-details inside its ibo-extension-details--information--description in the setup. We need to only affect direct children +.ibo-extension-details:has(>.ibo-extension-details--actions input:is([type="checkbox"], [type="radio"]):checked){ + &>.ibo-extension-details--information>.ibo-extension-details--information--label .ibo-badge.unchecked { + display: none; + } +} +//Merging the two lines below with :is([type="checkbox"], [type="radio"]) will generate a warning in scss compiler +.ibo-extension-details:has(>.ibo-extension-details--actions input[type="checkbox"]:not(:checked)), +.ibo-extension-details:has(>.ibo-extension-details--actions input[type="radio"]:not(:checked)) { + &>.ibo-extension-details--information>.ibo-extension-details--information--label .ibo-badge.checked { + display: none; + } +} + + +.ibo-extension-details--actions > button { + padding: $ibo-extension-details--actions--button--padding-y $ibo-extension-details--actions--button--padding-x; +} + +.ibo-extension-details--actions:has(.toggler-install:not(:disabled)) .ibo-popover-menu--section a[data-resource-id="force_uninstall"] { + display: none; +} + +.ibo-extension-details .ibo-popover-menu ~ .ibo-button{ + visibility: hidden; +} +.ibo-extension-details .ibo-popover-menu:has(.ibo-popover-menu--item) ~ .ibo-button{ + visibility: visible; +} + +.ibo-extension-details .ibo-toggler--wrapper:has(.ibo-toggler.ibo-is-hidden){ + visibility: hidden; +} diff --git a/css/setup.css b/css/setup.css index 6b29ab0058..7afceeae24 100644 --- a/css/setup.css +++ b/css/setup.css @@ -15,8 +15,8 @@ * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License - */:root{--skeleton-start-color: #e1e7ec;--skeleton-stop-color: #cfd8dc}.ibo-panel.ibo-is-selectable:hover .ibo-panel--body::after{font-family:"Font Awesome 5 Free";font-weight:400;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.dataTables_scrollHead thead tr th.sorting::after,.selectize-input .attribute-set-item.item-add::before,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active .attribute-set-item.item-add::before,.selectize-input .attribute-set-item.item-remove::before,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active .attribute-set-item.item-remove::before,.ibo-breadcrumbs--item:not(:last-child)::after,.ibo-breadcrumbs--previous-items-list-toggler:not(:last-child)::after,.ibo-panel.ibo-is-selectable .ibo-panel--body::after,.ibo-panel.ibo-is-selected .ibo-panel--body::after,.ibo-prop--apply.ui-state-error:after,.ibo-sort-order::after,.ibo-dashboard--slider:before,.ibo-dashboard--slider:after,.ibo-bulk--bulk-modify--incompatible-attribute:before,.ibo-linked-set--bulk-tooltip-info:before,.ibo-tab-container--tab-header.ibo-drag-in>a::after,.ibo-drag-in.ibo-tab-container--extra-tabs-container>a::after,.collapsable-options [data-role="setup-collapsable-options--toggler"]::before,#params_summary div.closed .title::before,#params_summary div:not(.closed) .title::before{font-family:"Font Awesome 5 Free";font-weight:900;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.common-is-fullwidth{width:100%}.common-font-size-50{font-size:0.83rem}.common-font-size-100{font-size:1rem}.common-font-size-150{font-size:1.17rem}.common-font-size-200{font-size:1.33rem}.common-font-size-250{font-size:1.5rem}.common-font-size-300{font-size:1.67rem}.common-font-size-350{font-size:1.83rem}.common-font-size-400{font-size:2rem}.common-font-size-450{font-size:2.5rem}.common-font-size-500{font-size:3rem}.common-font-size-550{font-size:4rem}.common-font-weight-100{font-weight:100}.common-font-weight-200{font-weight:200}.common-font-weight-300{font-weight:300}.common-font-weight-400{font-weight:400}.common-font-weight-500{font-weight:500}.common-font-weight-600{font-weight:600}.common-font-weight-700{font-weight:700}.common-font-weight-800{font-weight:800}.common-font-weight-900{font-weight:900}.common-font-weight-950{font-weight:950}.common-font-ral-nor-50{font-size:0.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-nor-100{font-size:1rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-nor-150{font-size:1.17rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-nor-200{font-size:1.33rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-nor-250{font-size:1.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-nor-300{font-size:1.67rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-nor-350{font-size:1.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-nor-400{font-size:2rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-nor-450{font-size:2.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-nor-500{font-size:3rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-nor-550{font-size:4rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-med-50{font-size:0.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-med-100{font-size:1rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-med-150{font-size:1.17rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-med-200{font-size:1.33rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-med-250{font-size:1.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-med-300{font-size:1.67rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-med-350{font-size:1.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-med-400{font-size:2rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-med-450{font-size:2.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-med-500{font-size:3rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-med-550{font-size:4rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-bol-50{font-size:0.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-bol-100{font-size:1rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-bol-150{font-size:1.17rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-bol-200{font-size:1.33rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-bol-250{font-size:1.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-bol-300{font-size:1.67rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-bol-350{font-size:1.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-bol-400{font-size:2rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-bol-450{font-size:2.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-bol-500{font-size:3rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-bol-550{font-size:4rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-sembol-50{font-size:0.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-sembol-100{font-size:1rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-sembol-150{font-size:1.17rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-sembol-200{font-size:1.33rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-sembol-250{font-size:1.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-sembol-300{font-size:1.67rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-sembol-350{font-size:1.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-sembol-400{font-size:2rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-sembol-450{font-size:2.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-sembol-500{font-size:3rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-sembol-550{font-size:4rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-ita-50{font-size:0.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-ita-100{font-size:1rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-ita-150{font-size:1.17rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-ita-200{font-size:1.33rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-ita-250{font-size:1.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-ita-300{font-size:1.67rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-ita-350{font-size:1.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-ita-400{font-size:2rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-ita-450{font-size:2.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-ita-500{font-size:3rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-ita-550{font-size:4rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-code-50{font-size:0.83rem;font-family:monospace;font-weight:400}.common-font-code-100{font-size:1rem;font-family:monospace;font-weight:400}.common-font-code-150{font-size:1.17rem;font-family:monospace;font-weight:400}.common-font-code-200{font-size:1.33rem;font-family:monospace;font-weight:400}.common-font-code-250{font-size:1.5rem;font-family:monospace;font-weight:400}.common-font-code-300{font-size:1.67rem;font-family:monospace;font-weight:400}.common-font-code-350{font-size:1.83rem;font-family:monospace;font-weight:400}.common-font-code-400{font-size:2rem;font-family:monospace;font-weight:400}.common-font-code-450{font-size:2.5rem;font-family:monospace;font-weight:400}.common-font-code-500{font-size:3rem;font-family:monospace;font-weight:400}.common-font-code-550{font-size:4rem;font-family:monospace;font-weight:400}@font-face{font-family:Raleway;font-weight:100;font-style:normal;font-display:swap;src:local("Raleway Thin"), url("../node_modules/@fontsource/raleway/files/raleway-all-100-normal.woff") format("woff")}@font-face{font-family:Raleway;font-weight:100;font-style:italic;font-display:swap;src:local("Raleway Thin"), url("../node_modules/@fontsource/raleway/files/raleway-all-100-italic.woff") format("woff")}@font-face{font-family:Raleway;font-weight:200;font-style:normal;font-display:swap;src:local("Raleway ExtraLight"), url("../node_modules/@fontsource/raleway/files/raleway-all-200-normal.woff") format("woff")}@font-face{font-family:Raleway;font-weight:200;font-style:italic;font-display:swap;src:local("Raleway ExtraLight"), url("../node_modules/@fontsource/raleway/files/raleway-all-200-italic.woff") format("woff")}@font-face{font-family:Raleway;font-weight:300;font-style:normal;font-display:swap;src:local("Raleway Light"), url("../node_modules/@fontsource/raleway/files/raleway-all-300-normal.woff") format("woff")}@font-face{font-family:Raleway;font-weight:300;font-style:italic;font-display:swap;src:local("Raleway Light"), url("../node_modules/@fontsource/raleway/files/raleway-all-300-italic.woff") format("woff")}@font-face{font-family:Raleway;font-weight:400;font-style:normal;font-display:swap;src:local("Raleway"), url("../node_modules/@fontsource/raleway/files/raleway-all-400-normal.woff") format("woff")}@font-face{font-family:Raleway;font-weight:400;font-style:italic;font-display:swap;src:local("Raleway"), url("../node_modules/@fontsource/raleway/files/raleway-all-400-italic.woff") format("woff")}@font-face{font-family:Raleway;font-weight:500;font-style:normal;font-display:swap;src:local("Raleway Medium"), url("../node_modules/@fontsource/raleway/files/raleway-all-500-normal.woff") format("woff")}@font-face{font-family:Raleway;font-weight:500;font-style:italic;font-display:swap;src:local("Raleway Medium"), url("../node_modules/@fontsource/raleway/files/raleway-all-500-italic.woff") format("woff")}@font-face{font-family:Raleway;font-weight:600;font-style:normal;font-display:swap;src:local("Raleway SemiBold"), url("../node_modules/@fontsource/raleway/files/raleway-all-600-normal.woff") format("woff")}@font-face{font-family:Raleway;font-weight:600;font-style:italic;font-display:swap;src:local("Raleway SemiBold"), url("../node_modules/@fontsource/raleway/files/raleway-all-600-italic.woff") format("woff")}@font-face{font-family:Raleway;font-weight:700;font-style:normal;font-display:swap;src:local("Raleway"), url("../node_modules/@fontsource/raleway/files/raleway-all-700-normal.woff") format("woff")}@font-face{font-family:Raleway;font-weight:700;font-style:italic;font-display:swap;src:local("Raleway"), url("../node_modules/@fontsource/raleway/files/raleway-all-700-italic.woff") format("woff")}@font-face{font-family:Raleway;font-weight:800;font-style:normal;font-display:swap;src:local("Raleway ExtraBold"), url("../node_modules/@fontsource/raleway/files/raleway-all-800-normal.woff") format("woff")}@font-face{font-family:Raleway;font-weight:800;font-style:italic;font-display:swap;src:local("Raleway ExtraBold"), url("../node_modules/@fontsource/raleway/files/raleway-all-800-italic.woff") format("woff")}@font-face{font-family:Raleway;font-weight:900;font-style:normal;font-display:swap;src:local("Raleway Black"), url("../node_modules/@fontsource/raleway/files/raleway-all-900-normal.woff") format("woff")}@font-face{font-family:Raleway;font-weight:900;font-style:italic;font-display:swap;src:local("Raleway Black"), url("../node_modules/@fontsource/raleway/files/raleway-all-900-italic.woff") format("woff")}:root{--ibo-color-white-100: white;--ibo-color-white-200: #f2f2f2;--ibo-color-transparent: rgba(255, 255, 255, 0);--ibo-color-grey-50: #fcfcfd;--ibo-color-grey-100: #f8f9fa;--ibo-color-grey-200: #e1e7ec;--ibo-color-grey-300: #d5dde5;--ibo-color-grey-400: #ccd4db;--ibo-color-grey-500: #aebecd;--ibo-color-grey-600: #929fb1;--ibo-color-grey-700: #6e7a8a;--ibo-color-grey-800: #404b5a;--ibo-color-grey-900: #212934;--ibo-color-grey-950: #141a22;--ibo-color-blue-grey-50: #f1f5f8;--ibo-color-blue-grey-100: #cfd8dc;--ibo-color-blue-grey-200: #b0bec5;--ibo-color-blue-grey-300: #90a4ae;--ibo-color-blue-grey-400: #78909c;--ibo-color-blue-grey-500: #607d8b;--ibo-color-blue-grey-600: #546e7a;--ibo-color-blue-grey-700: #455a64;--ibo-color-blue-grey-800: #37474f;--ibo-color-blue-grey-900: #263238;--ibo-color-blue-grey-950: #1b2428;--ibo-color-blue-100: #ebf8ff;--ibo-color-blue-200: #bee3f8;--ibo-color-blue-300: #90cef4;--ibo-color-blue-400: #63b4ed;--ibo-color-blue-500: #429ae1;--ibo-color-blue-600: #3182ce;--ibo-color-blue-700: #2b6bb0;--ibo-color-blue-800: #2c5382;--ibo-color-blue-900: #2a4265;--ibo-color-blue-950: #253750;--ibo-color-cyan-100: #c9eef2;--ibo-color-cyan-200: #80deea;--ibo-color-cyan-300: #4dd0e1;--ibo-color-cyan-400: #26c5da;--ibo-color-cyan-500: #00bbd4;--ibo-color-cyan-600: #00aac1;--ibo-color-cyan-700: #0096a7;--ibo-color-cyan-800: #00838f;--ibo-color-cyan-900: #006164;--ibo-color-cyan-950: #003636;--ibo-color-green-100: #dcedc8;--ibo-color-green-200: #c5e1a5;--ibo-color-green-300: #aed581;--ibo-color-green-400: #9ccc65;--ibo-color-green-500: #8ac34a;--ibo-color-green-600: #7cb342;--ibo-color-green-700: #689f38;--ibo-color-green-800: #558b2f;--ibo-color-green-900: #33691e;--ibo-color-green-950: #235816;--ibo-color-orange-100: floralwhite;--ibo-color-orange-200: #feebc8;--ibo-color-orange-300: #fbd38d;--ibo-color-orange-400: #f6ae55;--ibo-color-orange-500: #ea7d1e;--ibo-color-orange-600: #dd6c20;--ibo-color-orange-700: #c05621;--ibo-color-orange-800: #9c4221;--ibo-color-orange-900: #7b341e;--ibo-color-orange-950: #572819;--ibo-color-red-100: #fce8e8;--ibo-color-red-200: #fed7d7;--ibo-color-red-300: #feb2b2;--ibo-color-red-400: #fc8181;--ibo-color-red-500: #f56565;--ibo-color-red-600: #e53e3e;--ibo-color-red-700: #c53030;--ibo-color-red-800: #9b2c2c;--ibo-color-red-900: #742a2a;--ibo-color-red-950: #491d1d;--ibo-color-pink-100: #fff5f7;--ibo-color-pink-200: #fed7e2;--ibo-color-pink-300: #fbb6ce;--ibo-color-pink-400: #f688b4;--ibo-color-pink-500: #ed64a6;--ibo-color-pink-600: #d53f8c;--ibo-color-pink-700: #b83280;--ibo-color-pink-800: #97266d;--ibo-color-pink-900: #702459;--ibo-color-pink-950: #511a40;--ibo-color-yellow-100: ivory;--ibo-color-yellow-200: #fefcbf;--ibo-color-yellow-300: #faf089;--ibo-color-yellow-400: #f6e05e;--ibo-color-yellow-500: #ecc94b;--ibo-color-yellow-600: #d69e2e;--ibo-color-yellow-700: #b7791f;--ibo-color-yellow-800: #975a16;--ibo-color-yellow-900: #744210;--ibo-color-yellow-950: #4e2a09;--ibo-color-purple-100: #ede9fe;--ibo-color-purple-200: #ddd6fe;--ibo-color-purple-300: #c4b5fd;--ibo-color-purple-400: #a78bfa;--ibo-color-purple-500: #8b5cf6;--ibo-color-purple-600: #7c3aed;--ibo-color-purple-700: #6d28d9;--ibo-color-purple-800: #5b21b6;--ibo-color-purple-900: #4c1d95;--ibo-color-purple-950: #371371}:root{--ibo-color-primary-100: floralwhite;--ibo-color-primary-200: #feebc8;--ibo-color-primary-300: #fbd38d;--ibo-color-primary-400: #f6ae55;--ibo-color-primary-500: #ea7d1e;--ibo-color-primary-600: #dd6c20;--ibo-color-primary-700: #c05621;--ibo-color-primary-800: #9c4221;--ibo-color-primary-900: #7b341e;--ibo-color-primary-950: #572819;--ibo-color-secondary-100: #f8f9fa;--ibo-color-secondary-200: #e1e7ec;--ibo-color-secondary-300: #d5dde5;--ibo-color-secondary-400: #ccd4db;--ibo-color-secondary-500: #aebecd;--ibo-color-secondary-600: #929fb1;--ibo-color-secondary-700: #6e7a8a;--ibo-color-secondary-800: #404b5a;--ibo-color-secondary-900: #212934;--ibo-color-secondary-950: #141a22;--ibo-color-information-100: #ebf8ff;--ibo-color-information-200: #bee3f8;--ibo-color-information-300: #90cef4;--ibo-color-information-400: #63b4ed;--ibo-color-information-500: #429ae1;--ibo-color-information-600: #3182ce;--ibo-color-information-700: #2b6bb0;--ibo-color-information-800: #2c5382;--ibo-color-information-900: #2a4265;--ibo-color-information-950: #253750;--ibo-color-success-100: #dcedc8;--ibo-color-success-200: #c5e1a5;--ibo-color-success-300: #aed581;--ibo-color-success-400: #9ccc65;--ibo-color-success-500: #8ac34a;--ibo-color-success-600: #7cb342;--ibo-color-success-700: #689f38;--ibo-color-success-800: #558b2f;--ibo-color-success-900: #33691e;--ibo-color-success-950: #235816;--ibo-color-warning-100: floralwhite;--ibo-color-warning-200: #feebc8;--ibo-color-warning-300: #fbd38d;--ibo-color-warning-400: #f6ae55;--ibo-color-warning-500: #ea7d1e;--ibo-color-warning-600: #dd6c20;--ibo-color-warning-700: #c05621;--ibo-color-warning-800: #9c4221;--ibo-color-warning-900: #7b341e;--ibo-color-warning-950: #572819;--ibo-color-danger-100: #fce8e8;--ibo-color-danger-200: #fed7d7;--ibo-color-danger-300: #feb2b2;--ibo-color-danger-400: #fc8181;--ibo-color-danger-500: #f56565;--ibo-color-danger-600: #e53e3e;--ibo-color-danger-700: #c53030;--ibo-color-danger-800: #9b2c2c;--ibo-color-danger-900: #742a2a;--ibo-color-danger-950: #491d1d;--ibo-color-error-100: #fce8e8;--ibo-color-error-200: #fed7d7;--ibo-color-error-300: #feb2b2;--ibo-color-error-400: #fc8181;--ibo-color-error-500: #f56565;--ibo-color-error-600: #e53e3e;--ibo-color-error-700: #c53030;--ibo-color-error-800: #9b2c2c;--ibo-color-error-900: #742a2a;--ibo-color-error-950: #491d1d;--ibo-caselog-color-highlight-1: #689f38;--ibo-caselog-color-highlight-2: #b83280;--ibo-caselog-color-highlight-3: #f6ae55;--ibo-caselog-color-highlight-4: #3182ce;--ibo-caselog-color-highlight-5: #80deea}:root{--ibo-lifecycle-new-state-primary-color: #2c5382;--ibo-lifecycle-new-state-secondary-color: white;--ibo-lifecycle-neutral-state-primary-color: #2c5382;--ibo-lifecycle-neutral-state-secondary-color: white;--ibo-lifecycle-waiting-state-primary-color: #f6ae55;--ibo-lifecycle-waiting-state-secondary-color: white;--ibo-lifecycle-success-state-primary-color: #689f38;--ibo-lifecycle-success-state-secondary-color: white;--ibo-lifecycle-failure-state-primary-color: #b83280;--ibo-lifecycle-failure-state-secondary-color: white;--ibo-lifecycle-frozen-state-primary-color: #e1e7ec;--ibo-lifecycle-frozen-state-secondary-color: #6e7a8a;--ibo-lifecycle-active-state-primary-color: #689f38;--ibo-lifecycle-active-state-secondary-color: white;--ibo-lifecycle-inactive-state-primary-color: #f6ae55;--ibo-lifecycle-inactive-state-secondary-color: white}:root{--skeleton-start-color: #e1e7ec;--skeleton-stop-color: #cfd8dc}:root{--ibo-border-radius-100: 1px;--ibo-border-radius-300: 3px;--ibo-border-radius-500: 5px;--ibo-border-radius-700: 10px;--ibo-border-radius-900: 16px;--ibo-border-radius-full: 100%}:root{--ibo-depression-100: inset 0 1px 1px 0 rgba(0, 0, 0, 0.15)}:root{--ibo-elevation-100: 0 1px 2px rgba(0, 0, 0, 0.25), 0 1px 3px rgba(0, 0, 0, 0.12);--ibo-elevation-200: 0 2px 4px rgba(0, 0, 0, 0.12), 0 3px 6px rgba(0, 0, 0, 0.15);--ibo-elevation-300: 0 3px 6px rgba(0, 0, 0, 0.1), 0 10px 20px rgba(0, 0, 0, 0.15);--ibo-elevation-400: 0 5px 10px rgba(0, 0, 0, 0.05), 0 15px 25px rgba(0, 0, 0, 0.15);--ibo-elevation-500: 0 20px 40px rgba(0, 0, 0, 0.2)}:root{--ibo-size-0: 0;--ibo-size-50: 2px;--ibo-size-100: 4px;--ibo-size-150: 8px;--ibo-size-200: 12px;--ibo-size-250: 16px;--ibo-size-300: 24px;--ibo-size-350: 32px;--ibo-size-400: 48px;--ibo-size-450: 64px;--ibo-size-500: 96px;--ibo-size-550: 128px;--ibo-size-600: 192px;--ibo-size-650: 256px;--ibo-size-700: 384px;--ibo-size-750: 512px;--ibo-size-800: 640px;--ibo-size-850: 768px;--ibo-size-900: 896px}:root{--ibo-spacing-0: 0;--ibo-spacing-100: 2px;--ibo-spacing-200: 4px;--ibo-spacing-300: 8px;--ibo-spacing-400: 12px;--ibo-spacing-500: 16px;--ibo-spacing-600: 24px;--ibo-spacing-700: 32px;--ibo-spacing-800: 48px;--ibo-spacing-900: 64px;--ibo-spacing-950: 96px}:root{--ibo-font-size-50: 0.83rem;--ibo-font-size-100: 1rem;--ibo-font-size-150: 1.17rem;--ibo-font-size-200: 1.33rem;--ibo-font-size-250: 1.5rem;--ibo-font-size-300: 1.67rem;--ibo-font-size-350: 1.83rem;--ibo-font-size-400: 2rem;--ibo-font-size-450: 2.5rem;--ibo-font-size-500: 3rem;--ibo-font-size-550: 4rem}:root{--ibo-font-weight-100: 100;--ibo-font-weight-200: 200;--ibo-font-weight-300: 300;--ibo-font-weight-400: 400;--ibo-font-weight-500: 500;--ibo-font-weight-600: 600;--ibo-font-weight-700: 700;--ibo-font-weight-800: 800;--ibo-font-weight-900: 900;--ibo-font-weight-950: 950}:root{--ibo-font-family-base: Raleway;--ibo-font-family-monospace: monospace;--ibo-font-family-code: monospace}#ibo-setup-licenses--components-list{border-radius:3px}.ibo-welcome-popup--stack-item{border-radius:4px}.ibo-datatable .ibo-field-badge::before{border-radius:100%}.ibo-text.ibo-is-primary{color:#9c4221}.ibo-text.ibo-is-secondary,.ui-dialog .ibo-text.ui-button,.ibo-text.ui-datepicker-current,.ibo-text.ui-datepicker-close{color:#404b5a}.ibo-text.ibo-is-neutral,.ui-dialog .ibo-text.ui-button.ui-dialog-titlebar-close{color:#404b5a}.ibo-text.ibo-is-information{color:#2c5382}.ibo-text.ibo-is-success{color:#558b2f}.ibo-text.ibo-is-failure{color:#9b2c2c}.ibo-text.ibo-is-warning{color:#9c4221}.ibo-text.ibo-is-danger{color:#9b2c2c}.ibo-text.ibo-is-grey{color:#404b5a}.ibo-text.ibo-is-blue-grey{color:#37474f}.ibo-text.ibo-is-blue{color:#2c5382}.ibo-text.ibo-is-cyan{color:#00838f}.ibo-text.ibo-is-green{color:#558b2f}.ibo-text.ibo-is-orange{color:#9c4221}.ibo-text.ibo-is-red{color:#9b2c2c}.ibo-text.ibo-is-pink{color:#97266d}.ibo-class-icon.ibo-is-small{width:32px;min-width:32px;max-height:32px}.ibo-class-icon.ibo-is-medium{width:48px;min-width:48px;max-height:48px}.ibo-class-icon.ibo-is-large{width:64px;min-width:64px;max-height:64px}.ibo-activity-panel--tab-title-decoration{box-shadow:inset 0 1px 1px 0 rgba(0, 0, 0, 0.15)}.ibo-top-bar,.ibo-tab-container--extra-tabs-list{box-shadow:0 1px 2px rgba(0, 0, 0, 0.25), 0 1px 3px rgba(0, 0, 0, 0.12)}.ibo-breadcrumbs--previous-items-list,.ibo-quick-create--input.selectize-control.single .selectize-dropdown,.ibo-popover-menu,.ui-menu,.ui-multiselect-menu,.ibo-input-select-icon--menu,.graph_config .toolkit_menu.graph>ul>li ul,.ibo-activity-panel--filter-options{box-shadow:0 3px 6px rgba(0, 0, 0, 0.1), 0 10px 20px rgba(0, 0, 0, 0.15)}html.ibo-has-fullscreen-descendant{position:fixed !important;width:0 !important;height:0 !important}body.ibo-has-fullscreen-descendant{width:0 !important;height:0 !important;overflow:hidden !important}.ibo-has-fullscreen-descendant{position:static !important;overflow:visible !important;z-index:1050 !important}.ibo-is-fullscreen{position:absolute;top:0 !important;left:0 !important;margin:0 !important;padding:0 !important;width:100vw;height:100vh;overflow:auto;z-index:1050}.ibo-sticky-sentinel{position:absolute;left:0;right:0;visibility:hidden}.ibo-sticky-sentinel-top{top:0;height:0}.ibo-sticky-sentinel-bottom{bottom:0;height:0}:root{--ibo-hyperlink-color: #c05621;--ibo-hyperlink-text-decoration: none;--ibo-hyperlink-color--on-hover: #9c4221;--ibo-hyperlink-text-decoration--on-hover: none;--ibo-hyperlink-color--on-active: #7b341e;--ibo-hyperlink-text-decoration--on-active: none}.ibo-text-truncated-with-ellipsis,.ui-dialog .ui-dialog-title,.ibo-button--label,.ibo-breadcrumbs--item-label,.ibo-quick-create--compartment-element,.ibo-quick-create--compartment-results--element>.option,.ibo-global-search--compartment-element,.ibo-dashlet-badge--action-list-label,.ibo-input-select--autocomplete-item-txt,.attribute-set .attribute-set-item,.selectize-control.multi .selectize-input.ibo-input-set .attribute-set-item,.selectize-control.multi .ibo-quick-create--input.selectize-control.single .ibo-input-set.selectize-input.input-active .attribute-set-item,.ibo-quick-create--input.selectize-control.single .selectize-control.multi .ibo-input-set.selectize-input.input-active .attribute-set-item,.attribute-set .attribute-set-item>*,.selectize-control.multi .selectize-input.ibo-input-set .attribute-set-item>*,.selectize-control.multi .ibo-quick-create--input.selectize-control.single .ibo-input-set.selectize-input.input-active .attribute-set-item>*,.ibo-quick-create--input.selectize-control.single .selectize-control.multi .ibo-input-set.selectize-input.input-active .attribute-set-item>*,.ibo-navigation-menu--menu-group-title,.ibo-top-bar--toolbar-dashboard-title,.ibo-tab-container--tab-toggler,.ibo-tab-container--extra-tabs-list-toggler,.ibo-tab-container--tab-toggler-label,.ibo-tab-container--extra-tab-toggler,.ibo-object-details>.ibo-panel--header .ibo-panel--subtitle,.ibo-object-details>.ibo-object-summary--header .ibo-panel--subtitle,.ibo-activity-panel--tab-title-text,.ibo-activity-panel--filter-option,.ibo-welcome-popup--stack-item-title{white-space:nowrap;overflow-x:hidden;text-overflow:ellipsis}.dataTables_paginate a.paginate_button,.ibo-dashlet-badge--action-list:hover,.ibo-dashlet-badge--action-list:active,.ibo-field--fullscreen-toggler,.ibo-input-select--action-buttons a,.search_form_handler a,.ibo-navigation-menu--menu-filter-clear,.ibo-navigation-menu--menu-filter-hint-close,.ibo-tab-container--tab-toggler,.ibo-tab-container--extra-tabs-list-toggler,.ibo-activity-panel--load-entries-button,.ibo-welcome-popup--stack-item-title{color:inherit}.dataTables_paginate a.paginate_button:hover,.ibo-dashlet-badge--action-list:hover,.ibo-dashlet-badge--action-list:active:hover,.ibo-field--fullscreen-toggler:hover,.ibo-input-select--action-buttons a:hover,.search_form_handler a:hover,.ibo-navigation-menu--menu-filter-clear:hover,.ibo-navigation-menu--menu-filter-hint-close:hover,.ibo-tab-container--tab-toggler:hover,.ibo-tab-container--extra-tabs-list-toggler:hover,.ibo-activity-panel--load-entries-button:hover,.ibo-welcome-popup--stack-item-title:hover,.dataTables_paginate a.paginate_button:active,.ibo-dashlet-badge--action-list:hover:active,.ibo-dashlet-badge--action-list:active,.ibo-field--fullscreen-toggler:active,.ibo-input-select--action-buttons a:active,.search_form_handler a:active,.ibo-navigation-menu--menu-filter-clear:active,.ibo-navigation-menu--menu-filter-hint-close:active,.ibo-tab-container--tab-toggler:active,.ibo-tab-container--extra-tabs-list-toggler:active,.ibo-activity-panel--load-entries-button:active,.ibo-welcome-popup--stack-item-title:active{color:inherit}.ibo-navigation-menu--notifications-item .ibo-navigation-menu--notifications--item--content a{color:#c05621;text-decoration:none}.ibo-navigation-menu--notifications-item .ibo-navigation-menu--notifications--item--content a:hover{color:#9c4221;text-decoration:none}.ibo-navigation-menu--notifications-item .ibo-navigation-menu--notifications--item--content a:active{color:#7b341e;text-decoration:none}.ibo-is-broken-hyperlink{text-decoration:line-through;cursor:help}.ibo-is-disabled{cursor:not-allowed !important}.ibo-has-description::after{content:"🛈";padding-left:4px;vertical-align:top;cursor:pointer;color:#929fb1;font-size:0.7em}.ibo-is-code{background-color:#f2f2f2;padding:1.25rem 1.5rem}.ibo-is-html-content{}.ibo-is-html-content table{border-collapse:separate;border-spacing:2px}.ibo-is-html-content>code,.ibo-is-html-content code:not(.hljs){color:inherit}.ibo-is-html-content p{margin-top:0.25em;margin-bottom:0.25em}.ibo-is-html-content figure{display:inline-block;margin-left:2em !important;margin-right:2em !important}.ibo-is-html-content figure:not(:last-child){margin-bottom:2em !important}.ibo-is-html-content figure:not(:first-child){margin-top:2em !important}.ibo-is-fullwidth{width:100%}.ibo-welcome-popup--stack-item-icon,.ibo-panel--header-left,.ibo-panel--icon,.ibo-dashlet-header-static--icon-container,.ibo-input-image--image-view,.ibo-input-select--autocomplete-item-image,.ibo-pill,.ibo-title--icon,.ibo-datatable--toolbar-left,.ibo-datatable--toolbar-right,.ibo-field--fullscreen-toggler,.ibo-navigation-menu--bottom-part,.ibo-navigation-menu--user-info,.ibo-navigation-menu--user-info .ibo-navigation-menu--user-picture,.ibo-tab-container--tab-toggler,.ibo-tab-container--extra-tabs-list-toggler,.ibo-object-details--status-dot,.ibo-activity-panel--tab-title,.ibo-activity-panel--tab-toolbar-actions,.ibo-activity-panel--tab-toolbar-action,.ibo-activity-panel--body--placeholder-image,.ibo-activity-panel--body--placeholder-hint,.ibo-activity-panel--closed-cover,.ibo-caselog-entry-form--lock-icon,.ibo-activity-entry--medallion,.ibo-activity-panel--load-more-entries-container,.ibo-activity-panel--load-entries-button,.ibo-notifications--view-all--empty{display:flex;justify-content:center;align-items:center}.dataTables_paginate,.ibo-dashlet-badge--action-list,.ibo-input,.ui-autocomplete-input,.ui-multiselect,.dataTables_length select,.ui_tpicker_hour_slider>select,.ui_tpicker_minute_slider>select,.ui_tpicker_second_slider>select,select.ibo-input-select-placeholder,.ibo-datatableconfig--attributes-panel--per-page--input,.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content input[type="text"],.search_form_handler .sf_filter .sff_input_wrapper input[type="text"],.ibo-toolbar.ibo-toolbar--button,.ibo-activity-panel--tab-toolbar-left-actions,.ibo-activity-panel--tab-toolbar-middle-actions,.ibo-activity-panel--tab-toolbar-right-actions,.ibo-activity-panel--filter-option,.ibo-activity-panel--entry-forms-confirmation-preference,.ibo-caselog-entry-form--lock-indicator,.ibo-caselog-entry-form--action-buttons--main-actions,.ibo-welcome-popup--stack-item,#ibo_setup_container .ibo-title,#ibo_setup_container .ibo-setup--body .ibo-setup--button-bar,.ibo-setup--button-bar{display:flex;align-items:center}.ibo-dashlet-badge--action-create,.ibo-title,.ibo-title--subtitle,.ibo-object-details--status,.ibo-activity-panel--add-caselog-entry-button{display:flex;align-items:baseline}.ibo-breadcrumbs,.ibo-quick-create,.ibo-quick-create--head,.ibo-global-search,.ibo-global-search--head,.ibo-top-bar,.ibo-top-bar--quick-actions,.ibo-top-bar--toolbar,.ibo-top-bar--toolbar-dashboard-menu-toggler,.ibo-tab-container--tabs-list,.ibo-tab-container--tab-header,.ibo-tab-container--extra-tabs-container,.ibo-dashboard--top-bar,.ibo-welcome-popup--dialog{display:flex;align-items:stretch}.ibo-font-size-50,.ibo-field--fullscreen-toggler,.ibo-activity-panel--tab-title-draft-indicator,.ibo-activity-entry--sub-information{font-size:0.83rem}.ibo-font-size-100,.dataTables_paginate a.paginate_button,.selectize-add-option,.ibo-quick-create--drawer,.ibo-global-search--drawer,.ibo-dashlet-header-dynamic--label,.ibo-datatable--toolbar,.object-ref-icon.text_decoration,.object-ref-icon-disabled.text_decoration,.ibo-criterion-area,.ibo-dashboard-editor--properties table td .ibo-field,.ibo-dashboard-editor--properties table th .ibo-field,.ibo-dashboard--available-dashlets table td .ibo-field,.ibo-dashboard--available-dashlets table th .ibo-field,.ibo-dashlet--properties table td .ibo-field,.ibo-dashlet--properties table th .ibo-field,.ibo-caselog-list .ibo-collapsible-section .ibo-collapsible-section--header .ibo-collapsible-section--title,.ibo-caselog-list .ibo-collapsible-section .ibo-collapsible-section--body{font-size:1rem}.ibo-font-size-150,.ibo-alert,.ibo-breadcrumbs--item-icon,.ibo-panel--subtitle,.ibo-panel--body,.ibo-dashlet-badge--action-create,.ibo-spinner.ibo-is-small>.ibo-spinner--description,.ibo-prop-header,.ibo-field,.sf_results_placeholder,.ibo-input-file-select--container .ibo-input-file-select .ibo-input-file-select--file-name,.ibo-tab-container--tabs-list,.ibo-dashboard-editor--properties-subtitle,.ibo-dashboard--available-dashlet--title,.ibo-dashlet--properties--title,.ibo-activity-entry--medallion,.ibo-alert--body .ibo-collapsible-section .ibo-collapsible-section--header .ibo-collapsible-section--title,.ibo-alert--body .ibo-collapsible-section .ibo-collapsible-section--body{font-size:1.17rem}.ibo-font-size-200,.dataTables_paginate a.paginate_button.previous,.dataTables_paginate a.paginate_button.next{font-size:1.33rem}.ibo-font-size-250,.ibo-collapsible-section .ibo-collapsible-section--header .ibo-collapsible-section--title,.ibo-spinner.ibo-is-small>.ibo-spinner--icon,.ibo-spinner.ibo-is-medium>.ibo-spinner--description,.ibo-fieldset-legend,.ibo-dashboard-editor--properties-subtitle,.ibo-dashboard--available-dashlet--title,.ibo-dashlet--properties--title,legend,.ibo-top-bar--toolbar-dashboard-title,.ibo-tab-container--tab-container--label>span,.ibo-dashboard-editor--properties-title{font-size:1.5rem}.ibo-font-size-300,.ibo-title--for-object-details,.ibo-tab--temporary-remote-content--button{font-size:1.67rem}.ibo-font-size-350,.ibo-panel--title,.ibo-dashlet-header-static--body,.ibo-title-for-dashlet--title{font-size:1.83rem}.ibo-font-size-400,.ibo-spinner.ibo-is-large>.ibo-spinner--description{font-size:2rem}.ibo-font-size-450{font-size:2.5rem}.ibo-font-size-500,.ibo-spinner.ibo-is-medium>.ibo-spinner--icon{font-size:3rem}.ibo-font-size-550,.ibo-spinner.ibo-is-large>.ibo-spinner--icon{font-size:4rem}.ibo-font-weight-100{font-weight:100}.ibo-font-weight-200{font-weight:200}.ibo-font-weight-300{font-weight:300}.ibo-font-weight-400{font-weight:400}.ibo-font-weight-500{font-weight:500}.ibo-font-weight-600,.ibo-navigation-menu--notifications-show-all-multiple~.ibo-popover-menu .ibo-navigation-menu--notifications-show-all-multiple--counter,.ibo-navigation-menu--notifications-show-all-multiple~.ui-menu .ibo-navigation-menu--notifications-show-all-multiple--counter,.ibo-navigation-menu--notifications-show-all-multiple~.ui-multiselect-menu .ibo-navigation-menu--notifications-show-all-multiple--counter,.ibo-navigation-menu--notifications-show-all-multiple~.ibo-input-select-icon--menu .ibo-navigation-menu--notifications-show-all-multiple--counter,.graph_config .toolkit_menu.graph>ul>li .ibo-navigation-menu--notifications-show-all-multiple~ul .ibo-navigation-menu--notifications-show-all-multiple--counter,.ibo-dashlet-badge--body--tooltip-title,.ibo-field--label,.ibo-tab-container--extra-tab-toggler--tooltip-title{font-weight:600}.ibo-has-description::after,.ibo-font-weight-700,.ibo-alert .ibo-alert--title,.ibo-tab-container--tab-header.ui-tabs-active,.ui-tabs-active.ibo-tab-container--extra-tabs-container{font-weight:700}.ibo-font-weight-800{font-weight:800}.ibo-font-weight-900{font-weight:900}.ibo-font-weight-950{font-weight:950}.ibo-font-ral-nor-50,.ibo-navigation-menu--menu-filter-hotkey{font-size:0.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-nor-100,.ui-datepicker .ui-datepicker-title select,.ui-multiselect-checkboxes label,.ibo-input-select--autocomplete-item-txt,.ibo-datatableconfig--attributes-panel .ibo-panel--body,.ibo-navigation-menu--user-info .ibo-navigation-menu--user-organization,.ibo-linked-set--bulk-tooltip-info,.dataModelSchema text,.tooltipD3{font-size:1rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-nor-150,.ibo-input,.ui-autocomplete-input,.ui-multiselect,.dataTables_length select,.ui_tpicker_hour_slider>select,.ui_tpicker_minute_slider>select,.ui_tpicker_second_slider>select,select.ibo-input-select-placeholder,.ibo-datatableconfig--attributes-panel--per-page--input,.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content input[type="text"],.search_form_handler .sf_filter .sff_input_wrapper input[type="text"],.ibo-input-select.ibo-input-selectize input,.ibo-input-selectize.ui-multiselect input,.ui_tpicker_hour_slider>select.ibo-input-selectize input,.ui_tpicker_minute_slider>select.ibo-input-selectize input,.ui_tpicker_second_slider>select.ibo-input-selectize input,select.ibo-input-selectize.ibo-input-select-placeholder input,.ibo-title--subtitle,.ibo-navigation-menu--menu-nodes ul li>a,.ibo-navigation-menu--menu-nodes ul li>span,.ibo-navigation-menu--user-info .ibo-navigation-menu--user-notifications,.ibo-datamodel-viewer--details .ibo-panel--subtitle,.ibo-global-search--result--title{font-size:1.17rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-nor-200,.ibo-collapsible-section .ibo-collapsible-section--body,.ibo-navigation-menu--menu-group{font-size:1.33rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-nor-250,.ui-dialog-title,.ibo-navigation-menu--user-info .ibo-navigation-menu--user-welcome-message,#ibo_setup_container .ibo-setup--body .setup-content-title,#ibo_setup_container .ibo-setup--body h2,.setup-end-placeholder a{font-size:1.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-nor-300,.ibo-quick-create--input.selectize-control.single .selectize-input>input,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active>input,.ibo-quick-create--input.selectize-control.single .selectize-input>.item,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active>.item,.ibo-global-search--input,.ibo-global-search--input:hover,.ibo-global-search--input:focus,.ibo-global-search--input:active{font-size:1.67rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-nor-350,.ibo-navigation-menu--menu-nodes-title{font-size:1.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-nor-400,.ibo-quick-create--icon,.ibo-global-search--icon{font-size:2rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-nor-450{font-size:2.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-nor-500{font-size:3rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-nor-550{font-size:4rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-med-50{font-size:0.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-med-100,.dataTable th,.dataTable td,.ibo-breadcrumbs--item,.ibo-breadcrumbs--previous-items-list-toggler,.ibo-breadcrumbs--previous-item,.ibo-datatable[data-status="loading"] td,body{font-size:1rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-med-150,.ui-multiselect-checkboxes li,.ibo-welcome-popup--stack-item-title,.ibo-welcome-popup--message-description,.ibo-datamodel-viewer--breadcrumb{font-size:1.17rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-med-200{font-size:1.33rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-med-250,.ibo-dashlet-badge--action-list{font-size:1.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-med-300,.ibo-title--text{font-size:1.67rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-med-350{font-size:1.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-med-400,.ibo-datamodel-viewer--empty--text{font-size:2rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-med-450{font-size:2.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-med-500{font-size:3rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-med-550{font-size:4rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-bol-50,.ibo-navigation-menu--menu-filter-clear,.ibo-datamodel-viewer--icon--abstract:after{font-size:0.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-bol-100,.ui-multiselect-header ul,.ui-multiselect-checkboxes li.ui-multiselect-optgroup-label,.ibo-navigation-menu--menu-node-counter,#tooltipD3_top{font-size:1rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-bol-150,.ibo-object-summary--content--attributes--code,.ibo-alert.ibo-is-primary a,.ibo-alert.ibo-is-secondary a,.ui-dialog .ibo-alert.ui-button a,.ibo-alert.ui-datepicker-current a,.ibo-alert.ui-datepicker-close a,.ibo-alert.ibo-is-neutral a,.ui-dialog .ibo-alert.ui-button.ui-dialog-titlebar-close a,.ibo-toast.ibo-is-information a,.ibo-alert.ibo-is-information a,.ibo-toast.ibo-is-success a,.ibo-alert.ibo-is-success a,.ibo-alert.ibo-is-failure a,.ibo-toast.ibo-is-warning a,.ibo-alert.ibo-is-warning a,.ibo-toast.ibo-is-error a,.ibo-alert.ibo-is-danger a,.ibo-alert.ibo-is-grey a,.ibo-alert.ibo-is-blue-grey a,.ibo-alert.ibo-is-blue a,.ibo-alert.ibo-is-cyan a,.ibo-alert.ibo-is-green a,.ibo-alert.ibo-is-orange a,.ibo-alert.ibo-is-red a,.ibo-alert.ibo-is-pink a,.ibo-welcome-popup--message-title{font-size:1.17rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-bol-200,.ibo-dashlet-header-dynamic--count{font-size:1.33rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-bol-250,.ibo-dashboard--top-bar .ibo-dashboard--top-bar-title{font-size:1.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-bol-300{font-size:1.67rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-bol-350{font-size:1.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-bol-400{font-size:2rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-bol-450,.ibo-dashlet-badge--action-list-count{font-size:2.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-bol-500{font-size:3rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-bol-550{font-size:4rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-sembol-50{font-size:0.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-sembol-100,.dataTables_paginate a.paginate_button.current,.dataTables_scrollHead thead tr th,.ibo-button,.ui-dialog .ui-button,.ui-datepicker-current,.ui-datepicker-close,.ibo-datatable[data-status="loading"] th{font-size:1rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-sembol-150{font-size:1.17rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-sembol-200{font-size:1.33rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-sembol-250{font-size:1.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-sembol-300{font-size:1.67rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-sembol-350{font-size:1.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-sembol-400{font-size:2rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-sembol-450{font-size:2.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-sembol-500{font-size:3rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-sembol-550{font-size:4rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-ita-50,.ibo-navigation-menu--menu-filter-hint{font-size:0.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-ita-100,.ibo-quick-create--compartment--placeholder-hint,.ibo-global-search--compartment--placeholder-hint,.ibo-navigation-menu--menu--placeholder-hint,.ibo-activity-panel--body--placeholder-hint{font-size:1rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-ita-150{font-size:1.17rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-ita-200{font-size:1.33rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-ita-250{font-size:1.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-ita-300{font-size:1.67rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-ita-350{font-size:1.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-ita-400{font-size:2rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-ita-450{font-size:2.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-ita-500{font-size:3rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-ita-550{font-size:4rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-code-50{font-size:0.83rem;font-family:monospace;font-weight:400}.ibo-font-code-100,.ibo-datamodel-viewer--classname{font-size:1rem;font-family:monospace;font-weight:400}.ibo-is-code,.ibo-font-code-150,.ibo-input-text.ibo-is-code,textarea.ibo-is-code{font-size:1.17rem;font-family:monospace;font-weight:400}.ibo-font-code-200{font-size:1.33rem;font-family:monospace;font-weight:400}.ibo-font-code-250{font-size:1.5rem;font-family:monospace;font-weight:400}.ibo-font-code-300{font-size:1.67rem;font-family:monospace;font-weight:400}.ibo-font-code-350{font-size:1.83rem;font-family:monospace;font-weight:400}.ibo-font-code-400{font-size:2rem;font-family:monospace;font-weight:400}.ibo-font-code-450{font-size:2.5rem;font-family:monospace;font-weight:400}.ibo-font-code-500{font-size:3rem;font-family:monospace;font-weight:400}.ibo-font-code-550{font-size:4rem;font-family:monospace;font-weight:400}.ibo-add-margin-top-250{margin-top:12px}.ibo-welcome-popup--stack-item-icon{position:relative;border-radius:var(--ibo-border-radius-full);border:2px solid var(--ibo-color-grey-300);overflow:hidden}.ibo-welcome-popup--stack-item-icon>*{position:absolute;top:0;left:0;width:100%;height:100%;background-position:center;background-size:contain;background-color:var(--ibo-color-grey-500)}.ibo-is-visible{display:inherit !important;visibility:visible !important}.ibo-is-hidden{display:none !important}.ibo-is-transparent{opacity:0 !important}.ibo-is-opaque{opacity:1 !important}.content:not(:last-child),.ibo-is-html-content:not(:last-child){margin-bottom:1.5rem}/*! minireset.css v0.0.6 | MIT License | github.com/jgthms/minireset.css */html,body,p,ol,ul,li,dl,dt,dd,blockquote,figure,fieldset,legend,textarea,pre,iframe,hr,h1,h2,h3,h4,h5,h6{margin:0;padding:0}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal}ul{list-style:none}button,input,select,textarea{margin:0}html{box-sizing:border-box}*,*::before,*::after{box-sizing:inherit}img,video{height:auto;max-width:100%}iframe{border:0}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}td:not([align]),th:not([align]){text-align:inherit}html{background-color:white;font-size:16px;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;min-width:300px;overflow-x:hidden;overflow-y:auto;text-rendering:optimizeLegibility;text-size-adjust:100%}article,aside,figure,footer,header,hgroup,section{display:block}body,button,input,optgroup,select,textarea{font-family:"Raleway", "sans-serif", "system-ui"}code,pre{-moz-osx-font-smoothing:auto;-webkit-font-smoothing:auto;font-family:monospace}body{color:#212934;font-size:1rem;font-weight:500;line-height:1.5}a{color:#485fc7;cursor:pointer;text-decoration:none}a strong{color:currentColor}a:hover{color:#363636}code{background-color:whitesmoke;color:#da1039;font-size:0.875em;font-weight:normal;padding:0.25em 0.5em 0.25em}hr{background-color:whitesmoke;border:none;display:block;height:2px;margin:1.5rem 0}img{height:auto;max-width:100%}input[type="checkbox"],input[type="radio"]{vertical-align:baseline}small{font-size:0.875em}span{font-style:inherit;font-weight:inherit}strong{color:inherit;font-weight:700}fieldset{border:none}pre{-webkit-overflow-scrolling:touch;background-color:whitesmoke;color:#4a4a4a;font-size:0.875em;overflow-x:auto;padding:1.25rem 1.5rem;white-space:pre;word-wrap:normal}pre code{background-color:transparent;color:currentColor;font-size:1em;padding:0}table td,table th{vertical-align:top}table td:not([align]),table th:not([align]){text-align:inherit}table th{color:inherit}@keyframes spinAround{from{transform:rotate(0deg)}to{transform:rotate(359deg)}}.content li+li,.ibo-is-html-content li+li{margin-top:0.25em}.content p:not(:last-child),.ibo-is-html-content p:not(:last-child),.content dl:not(:last-child),.ibo-is-html-content dl:not(:last-child),.content ol:not(:last-child),.ibo-is-html-content ol:not(:last-child),.content ul:not(:last-child),.ibo-is-html-content ul:not(:last-child),.content blockquote:not(:last-child),.ibo-is-html-content blockquote:not(:last-child),.content pre:not(:last-child),.ibo-is-html-content pre:not(:last-child),.content table:not(:last-child),.ibo-is-html-content table:not(:last-child){margin-bottom:0}.content h1,.ibo-is-html-content h1,.content h2,.ibo-is-html-content h2,.content h3,.ibo-is-html-content h3,.content h4,.ibo-is-html-content h4,.content h5,.ibo-is-html-content h5,.content h6,.ibo-is-html-content h6{color:inherit;font-weight:600;line-height:1.125}.content h1,.ibo-is-html-content h1{font-size:2em;margin-bottom:0.5em}.content h1:not(:first-child),.ibo-is-html-content h1:not(:first-child){margin-top:1em}.content h2,.ibo-is-html-content h2{font-size:1.75em;margin-bottom:0.5714em}.content h2:not(:first-child),.ibo-is-html-content h2:not(:first-child){margin-top:1.1428em}.content h3,.ibo-is-html-content h3{font-size:1.5em;margin-bottom:0.6666em}.content h3:not(:first-child),.ibo-is-html-content h3:not(:first-child){margin-top:1.3333em}.content h4,.ibo-is-html-content h4{font-size:1.25em;margin-bottom:0.8em}.content h5,.ibo-is-html-content h5{font-size:1.125em;margin-bottom:0.8888em}.content h6,.ibo-is-html-content h6{font-size:1em;margin-bottom:1em}.content blockquote,.ibo-is-html-content blockquote{background-color:#e1e7ec;border-left:5px solid #dbdbdb;padding:1.25em 1.5em}.content ol,.ibo-is-html-content ol{list-style-position:outside;margin-left:2em;margin-top:1em}.content ol:not([type]),.ibo-is-html-content ol:not([type]){list-style-type:decimal}.content ol:not([type]).is-lower-alpha,.ibo-is-html-content ol:not([type]).is-lower-alpha{list-style-type:lower-alpha}.content ol:not([type]).is-lower-roman,.ibo-is-html-content ol:not([type]).is-lower-roman{list-style-type:lower-roman}.content ol:not([type]).is-upper-alpha,.ibo-is-html-content ol:not([type]).is-upper-alpha{list-style-type:upper-alpha}.content ol:not([type]).is-upper-roman,.ibo-is-html-content ol:not([type]).is-upper-roman{list-style-type:upper-roman}.content ul,.ibo-is-html-content ul{list-style:disc outside;margin-left:2em;margin-top:1em}.content ul ul,.ibo-is-html-content ul ul{list-style-type:circle;margin-top:0.5em}.content ul ul ul,.ibo-is-html-content ul ul ul{list-style-type:square}.content dd,.ibo-is-html-content dd{margin-left:2em}.content figure,.ibo-is-html-content figure{margin-left:2em;margin-right:2em;text-align:center}.content figure:not(:first-child),.ibo-is-html-content figure:not(:first-child){margin-top:2em}.content figure:not(:last-child),.ibo-is-html-content figure:not(:last-child){margin-bottom:2em}.content figure img,.ibo-is-html-content figure img{display:inline-block}.content figure figcaption,.ibo-is-html-content figure figcaption{font-style:italic}.content pre,.ibo-is-html-content pre{-webkit-overflow-scrolling:touch;overflow-x:auto;padding:1.25em 1.5em;white-space:pre;word-wrap:normal}.content sup,.ibo-is-html-content sup,.content sub,.ibo-is-html-content sub{font-size:75%}.content table,.ibo-is-html-content table{width:100%}.content table td,.ibo-is-html-content table td,.content table th,.ibo-is-html-content table th{border:"invalid on purpose";border-width:"invalid on purpose";padding:"invalid on purpose";vertical-align:top}.content table th,.ibo-is-html-content table th{color:"invalid on purpose"}.content table th:not([align]),.ibo-is-html-content table th:not([align]){text-align:inherit}.content table thead td,.ibo-is-html-content table thead td,.content table thead th,.ibo-is-html-content table thead th{border-width:"invalid on purpose";color:"invalid on purpose"}.content table tfoot td,.ibo-is-html-content table tfoot td,.content table tfoot th,.ibo-is-html-content table tfoot th{border-width:"invalid on purpose";color:"invalid on purpose"}.content table tbody tr:last-child td,.ibo-is-html-content table tbody tr:last-child td,.content table tbody tr:last-child th,.ibo-is-html-content table tbody tr:last-child th{border-bottom-width:1px}.content .tabs li+li,.ibo-is-html-content .tabs li+li{margin-top:0}.content.is-small,.is-small.ibo-is-html-content{font-size:0.75rem}.content.is-normal,.is-normal.ibo-is-html-content{font-size:1rem}.content.is-medium,.is-medium.ibo-is-html-content{font-size:1.25rem}.content.is-large,.is-large.ibo-is-html-content{font-size:1.5rem}.common-hljs-container{padding:0 !important;border:none !important}pre code.hljs{display:block;overflow-x:auto;padding:0.9rem !important}code.hljs{padding:4px 4px !important}.hljs{box-shadow:0 0px 3px 2px inset rgba(0, 0, 0, 0.4) !important;border-radius:3px !important;white-space:pre-wrap;border:none !important;color:#e0e2e4 !important;background:#282b2e !important}.hljs-keyword,.hljs-selector-tag,.hljs-literal,.hljs-selector-id{color:#93c763 !important}.hljs-number{color:#ffcd22 !important}.hljs-attribute{color:#668bb0}.hljs-regexp,.hljs-link{color:#d39745 !important}.hljs-meta{color:#557182 !important}.hljs-tag,.hljs-name,.hljs-bullet,.hljs-subst,.hljs-emphasis,.hljs-type,.hljs-built_in,.hljs-selector-attr,.hljs-selector-pseudo,.hljs-addition,.hljs-variable,.hljs-template-tag,.hljs-template-variable{color:#8cbbad !important}.hljs-string,.hljs-symbol{color:#ec7600 !important}.hljs-comment,.hljs-quote,.hljs-deletion{color:#818e96 !important}.hljs-selector-class{color:#A082BD !important}.hljs-keyword,.hljs-selector-tag,.hljs-literal,.hljs-doctag,.hljs-title,.hljs-section,.hljs-type,.hljs-name,.hljs-strong{font-weight:bold}.hljs-code,.hljs-title.class_,.hljs-class .hljs-title,.hljs-section{color:white !important}:root{--ck-color-base-foreground: #fafafa;--ck-color-base-background: #fff;--ck-color-base-border: #ccced1;--ck-color-base-action: #53a336;--ck-color-base-focus: #6cb5f9;--ck-color-base-text: #333;--ck-color-base-active: #2977ff;--ck-color-base-active-focus: #0d65ff;--ck-color-base-error: #db3700;--ck-color-focus-border-coordinates: 218, 81.8%, 56.9%;--ck-color-focus-border: hsl(var(--ck-color-focus-border-coordinates));--ck-color-focus-outer-shadow: #cae1fc;--ck-color-focus-disabled-shadow: #77baf84d;--ck-color-focus-error-shadow: #ff401f4d;--ck-color-text: var(--ck-color-base-text);--ck-color-shadow-drop: #00000026;--ck-color-shadow-drop-active: #0003;--ck-color-shadow-inner: #0000001a;--ck-color-button-default-background: transparent;--ck-color-button-default-hover-background: #f0f0f0;--ck-color-button-default-active-background: #f0f0f0;--ck-color-button-default-disabled-background: transparent;--ck-color-button-on-background: #f0f7ff;--ck-color-button-on-hover-background: #dbecff;--ck-color-button-on-active-background: #dbecff;--ck-color-button-on-disabled-background: #f0f2f4;--ck-color-button-on-color: #2977ff;--ck-color-button-action-background: var(--ck-color-base-action);--ck-color-button-action-hover-background: #4d9d30;--ck-color-button-action-active-background: #4d9d30;--ck-color-button-action-disabled-background: #7ec365;--ck-color-button-action-text: var(--ck-color-base-background);--ck-color-button-save: #008a00;--ck-color-button-cancel: #db3700;--ck-color-switch-button-off-background: #939393;--ck-color-switch-button-off-hover-background: #7d7d7d;--ck-color-switch-button-on-background: var(--ck-color-button-action-background);--ck-color-switch-button-on-hover-background: #4d9d30;--ck-color-switch-button-inner-background: var(--ck-color-base-background);--ck-color-switch-button-inner-shadow: #0000001a;--ck-color-dropdown-panel-background: var(--ck-color-base-background);--ck-color-dropdown-panel-border: var(--ck-color-base-border);--ck-color-dialog-background: var(--ck-custom-background);--ck-color-dialog-form-header-border: var(--ck-custom-border);--ck-color-input-background: var(--ck-color-base-background);--ck-color-input-border: var(--ck-color-base-border);--ck-color-input-error-border: var(--ck-color-base-error);--ck-color-input-text: var(--ck-color-base-text);--ck-color-input-disabled-background: #f2f2f2;--ck-color-input-disabled-border: var(--ck-color-base-border);--ck-color-input-disabled-text: #757575;--ck-color-list-background: var(--ck-color-base-background);--ck-color-list-button-hover-background: var(--ck-color-button-default-hover-background);--ck-color-list-button-on-background: var(--ck-color-button-on-color);--ck-color-list-button-on-background-focus: var(--ck-color-button-on-color);--ck-color-list-button-on-text: var(--ck-color-base-background);--ck-color-panel-background: var(--ck-color-base-background);--ck-color-panel-border: var(--ck-color-base-border);--ck-color-toolbar-background: var(--ck-color-base-background);--ck-color-toolbar-border: var(--ck-color-base-border);--ck-color-tooltip-background: var(--ck-color-base-text);--ck-color-tooltip-text: var(--ck-color-base-background);--ck-color-engine-placeholder-text: #707070;--ck-color-upload-bar-background: #6cb5f9;--ck-color-link-default: #0000f0;--ck-color-link-selected-background: #1fb0ff1a;--ck-color-link-fake-selection: #1fb0ff4d;--ck-color-highlight-background: #ff0;--ck-color-light-red: #fcc;--ck-disabled-opacity: .5;--ck-focus-outer-shadow-geometry: 0 0 0 3px;--ck-focus-outer-shadow: var(--ck-focus-outer-shadow-geometry) var(--ck-color-focus-outer-shadow);--ck-focus-disabled-outer-shadow: var(--ck-focus-outer-shadow-geometry) var(--ck-color-focus-disabled-shadow);--ck-focus-error-outer-shadow: var(--ck-focus-outer-shadow-geometry) var(--ck-color-focus-error-shadow);--ck-focus-ring: 1px solid var(--ck-color-focus-border);--ck-font-size-base: 13px;--ck-line-height-base: 1.84615;--ck-font-face: Helvetica, Arial, Tahoma, Verdana, Sans-Serif;--ck-font-size-tiny: .7em;--ck-font-size-small: .75em;--ck-font-size-normal: 1em;--ck-font-size-big: 1.4em;--ck-font-size-large: 1.8em;--ck-ui-component-min-height: 2.3em}.ck.ck-reset,.ck.ck-reset_all,.ck-reset_all :not(.ck-reset_all-excluded, .ck-reset_all-excluded *){box-sizing:border-box;vertical-align:middle;word-wrap:break-word;background:none;border:0;width:auto;height:auto;margin:0;padding:0;text-decoration:none;transition:none;position:static}.ck.ck-reset_all,.ck-reset_all :not(.ck-reset_all-excluded, .ck-reset_all-excluded *){border-collapse:collapse;font:normal normal normal var(--ck-font-size-base)/var(--ck-line-height-base) var(--ck-font-face);color:var(--ck-color-text);text-align:left;white-space:nowrap;cursor:auto;float:none}.ck-reset_all .ck-rtl :not(.ck-reset_all-excluded, .ck-reset_all-excluded *){text-align:right}.ck-reset_all iframe:not(.ck-reset_all-excluded *){vertical-align:inherit}.ck-reset_all textarea:not(.ck-reset_all-excluded *){white-space:pre-wrap}.ck-reset_all textarea:not(.ck-reset_all-excluded *),.ck-reset_all input[type="text"]:not(.ck-reset_all-excluded *),.ck-reset_all input[type="password"]:not(.ck-reset_all-excluded *){cursor:text}.ck-reset_all textarea[disabled]:not(.ck-reset_all-excluded *),.ck-reset_all input[type="text"][disabled]:not(.ck-reset_all-excluded *),.ck-reset_all input[type="password"][disabled]:not(.ck-reset_all-excluded *){cursor:default}.ck-reset_all fieldset:not(.ck-reset_all-excluded *){border:2px groove #dfdee3;padding:10px}.ck-reset_all button:not(.ck-reset_all-excluded *)::-moz-focus-inner{border:0;padding:0}.ck[dir="rtl"],.ck[dir="rtl"] .ck{text-align:right}:root{--ck-border-radius: 2px;--ck-rounded-corners-radius: 0}.ck-rounded-corners{--ck-rounded-corners-radius: var(--ck-border-radius)}:root{--ck-inner-shadow: 2px 2px 3px var(--ck-color-shadow-inner) inset;--ck-drop-shadow: 0 1px 2px 1px var(--ck-color-shadow-drop);--ck-drop-shadow-active: 0 3px 6px 1px var(--ck-color-shadow-drop-active);--ck-spacing-unit: .6em;--ck-spacing-extra-large: calc(var(--ck-spacing-unit) * 2);--ck-spacing-large: calc(var(--ck-spacing-unit) * 1.5);--ck-spacing-standard: var(--ck-spacing-unit);--ck-spacing-medium: calc(var(--ck-spacing-unit) * .8);--ck-spacing-medium-small: calc(var(--ck-spacing-unit) * .667);--ck-spacing-small: calc(var(--ck-spacing-unit) * .5);--ck-spacing-tiny: calc(var(--ck-spacing-unit) * .3);--ck-spacing-extra-tiny: calc(var(--ck-spacing-unit) * .16)}.ck-hidden{display:none !important}:root{--ck-z-default: 1;--ck-z-panel: calc(var(--ck-z-default) + 999);--ck-z-dialog: 9999}.ck-transitions-disabled,.ck-transitions-disabled *{transition:none !important}:root{--ck-powered-by-font-size: calc(var(--ck-font-size-base) * 7.5 / 13);--ck-powered-by-line-height: calc(var(--ck-font-size-base) * 10 / 13);--ck-powered-by-letter-spacing: calc(var(--ck-font-size-base) * -.2 / 13);--ck-powered-by-padding-vertical: 2px;--ck-powered-by-padding-horizontal: 4px;--ck-powered-by-text-color: #4f4f4f;--ck-powered-by-border-radius: var(--ck-border-radius);--ck-powered-by-background: #fff;--ck-powered-by-border-color: var(--ck-color-focus-border);--ck-powered-by-svg-width: 53;--ck-powered-by-svg-height: 10;--ck-powered-by-icon-width: calc(var(--ck-font-size-base) * var(--ck-powered-by-svg-width) / 13);--ck-powered-by-icon-height: calc(var(--ck-font-size-base) * var(--ck-powered-by-svg-height) / 13)}.ck.ck-balloon-panel.ck-powered-by-balloon{--ck-border-radius: var(--ck-powered-by-border-radius);box-shadow:none;background:var(--ck-powered-by-background);min-height:unset;z-index:calc(var(--ck-z-panel) - 1)}.ck.ck-balloon-panel.ck-powered-by-balloon .ck.ck-powered-by{line-height:var(--ck-powered-by-line-height)}.ck.ck-balloon-panel.ck-powered-by-balloon .ck.ck-powered-by a{cursor:pointer;opacity:0.66;filter:grayscale(80%);line-height:var(--ck-powered-by-line-height);padding:var(--ck-powered-by-padding-vertical) var(--ck-powered-by-padding-horizontal);align-items:center;display:flex}.ck.ck-balloon-panel.ck-powered-by-balloon .ck.ck-powered-by .ck-powered-by__label{font-size:var(--ck-powered-by-font-size);letter-spacing:var(--ck-powered-by-letter-spacing);text-transform:uppercase;cursor:pointer;color:var(--ck-powered-by-text-color);margin-right:4px;padding-left:2px;font-weight:bold;line-height:normal}.ck.ck-balloon-panel.ck-powered-by-balloon .ck.ck-powered-by .ck-icon{cursor:pointer;width:var(--ck-powered-by-icon-width);height:var(--ck-powered-by-icon-height);display:block}.ck.ck-balloon-panel.ck-powered-by-balloon .ck.ck-powered-by:hover a{filter:grayscale(0%);opacity:1}.ck.ck-balloon-panel.ck-powered-by-balloon[class*="position_inside"]{border-color:#0000}.ck.ck-balloon-panel.ck-powered-by-balloon[class*="position_border"]{border:var(--ck-focus-ring);border-color:var(--ck-powered-by-border-color)}:root{--ck-evaluation-badge-font-size: calc(var(--ck-font-size-base) * 7.5 / 13);--ck-evaluation-badge-line-height: calc(var(--ck-font-size-base) * 7.5 / 13);--ck-evaluation-badge-letter-spacing: calc(var(--ck-font-size-base) * -.2 / 13);--ck-evaluation-badge-padding-vertical: 2px;--ck-evaluation-badge-padding-horizontal: 4px;--ck-evaluation-badge-text-color: #4f4f4f;--ck-evaluation-badge-border-radius: var(--ck-border-radius);--ck-evaluation-badge-background: #fff;--ck-evaluation-badge-border-color: var(--ck-color-focus-border)}.ck.ck-balloon-panel.ck-evaluation-badge-balloon{--ck-border-radius: var(--ck-evaluation-badge-border-radius);box-shadow:none;background:var(--ck-evaluation-badge-background);min-height:unset;z-index:calc(var(--ck-z-panel) - 1)}.ck.ck-balloon-panel.ck-evaluation-badge-balloon .ck.ck-evaluation-badge{line-height:var(--ck-evaluation-badge-line-height);padding:var(--ck-evaluation-badge-padding-vertical) var(--ck-evaluation-badge-padding-horizontal)}.ck.ck-balloon-panel.ck-evaluation-badge-balloon .ck.ck-evaluation-badge .ck-evaluation-badge__label{font-size:var(--ck-evaluation-badge-font-size);letter-spacing:var(--ck-evaluation-badge-letter-spacing);text-transform:uppercase;color:var(--ck-evaluation-badge-text-color);padding:0 2px;font-weight:bold;line-height:normal;display:block}.ck.ck-balloon-panel.ck-evaluation-badge-balloon[class*="position_inside"]{border-color:#0000}.ck.ck-balloon-panel.ck-evaluation-badge-balloon[class*="position_border"]{border:var(--ck-focus-ring);border-color:var(--ck-evaluation-badge-border-color)}.ck.ck-responsive-form{padding:var(--ck-spacing-large)}.ck.ck-responsive-form:focus{outline:none}[dir="ltr"] .ck.ck-responsive-form>:not(:first-child){margin-left:var(--ck-spacing-standard)}[dir="rtl"] .ck.ck-responsive-form>:not(:last-child){margin-left:var(--ck-spacing-standard)}@media screen and (width <= 600px){.ck.ck-responsive-form{width:calc(.8 * var(--ck-input-width));padding:0}.ck.ck-responsive-form .ck-labeled-field-view{margin:var(--ck-spacing-large) var(--ck-spacing-large) 0}.ck.ck-responsive-form .ck-labeled-field-view .ck-input-text,.ck.ck-responsive-form .ck-labeled-field-view .ck-input-number{width:100%;min-width:0}.ck.ck-responsive-form .ck-labeled-field-view .ck-labeled-field-view__error{white-space:normal}.ck.ck-responsive-form>.ck-button:last-child,.ck.ck-responsive-form>.ck-button:nth-last-child(2){padding:var(--ck-spacing-standard);margin-top:var(--ck-spacing-large);border-radius:0}:is(.ck.ck-responsive-form>.ck-button:last-child, .ck.ck-responsive-form>.ck-button:nth-last-child(2)):not(:focus){border-top:1px solid var(--ck-color-base-border)}[dir="ltr"] :is(.ck.ck-responsive-form>.ck-button:last-child, .ck.ck-responsive-form>.ck-button:nth-last-child(2)){margin-left:0}[dir="rtl"] :is(.ck.ck-responsive-form>.ck-button:last-child, .ck.ck-responsive-form>.ck-button:nth-last-child(2)){margin-left:0}[dir="rtl"] :is(.ck.ck-responsive-form>.ck-button:last-child, .ck.ck-responsive-form>.ck-button:nth-last-child(2)):last-of-type{border-right:1px solid var(--ck-color-base-border)}.ck.ck-responsive-form .ck-button:after{content:"";z-index:1;width:0;position:absolute;top:-1px;bottom:-1px;right:-1px}.ck.ck-responsive-form .ck-button:nth-last-child(2):after{border-right:1px solid var(--ck-color-base-border)}.ck.ck-responsive-form .ck-button:focus:after{display:none}}.ck-vertical-form>.ck-button:nth-last-child(2):after{border-right:1px solid var(--ck-color-base-border)}.ck-vertical-form .ck-button:after{content:"";z-index:1;width:0;position:absolute;top:-1px;bottom:-1px;right:-1px}.ck-vertical-form .ck-button:focus:after{display:none}:root{--ck-form-default-width: 340px}.ck.ck-form{padding:0 0 var(--ck-spacing-large)}.ck.ck-form.ck-form_default-width{width:var(--ck-form-default-width)}.ck.ck-form:focus{outline:none}.ck.ck-form .ck.ck-input-text,.ck.ck-form .ck.ck-input-number{width:0;min-width:100%}.ck.ck-form .ck.ck-dropdown{min-width:100%}.ck.ck-form .ck.ck-dropdown .ck-dropdown__button:not(:focus){border:1px solid var(--ck-color-base-border)}.ck.ck-form .ck.ck-dropdown .ck-dropdown__button .ck-button__label{width:100%}@media screen and (width <= 600px){.ck.ck-form.ck-responsive-form .ck.ck-form__row.ck-form__row_with-submit{flex-direction:column;align-items:stretch;padding:0}}@media screen and (width <= 600px){.ck.ck-form.ck-responsive-form .ck.ck-form__row.ck-form__row_with-submit>.ck{margin:var(--ck-spacing-large) var(--ck-spacing-large) 0}}@media screen and (width <= 600px){.ck.ck-form.ck-responsive-form .ck.ck-form__row.ck-form__row_with-submit .ck-button_with-text{justify-content:center}}@media screen and (width <= 600px){.ck.ck-form.ck-responsive-form .ck.ck-form__row.ck-form__row_large-bottom-padding{padding-bottom:var(--ck-spacing-large)}}[dir="ltr"] .ck.ck-form.ck-responsive-form>:not(:first-child){margin-left:0}[dir="rtl"] .ck.ck-form.ck-responsive-form>:not(:last-child){margin-left:0}.ck.ck-aria-live-announcer{position:absolute;top:-10000px;left:-10000px}.ck.ck-aria-live-region-list{list-style-type:none}:root{--ck-accessibility-help-dialog-max-width: 600px;--ck-accessibility-help-dialog-max-height: 400px;--ck-accessibility-help-dialog-border-color: #ccced1;--ck-accessibility-help-dialog-code-background-color: #ededed;--ck-accessibility-help-dialog-kbd-shadow-color: #9c9c9c}.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content{padding:var(--ck-spacing-large);max-width:var(--ck-accessibility-help-dialog-max-width);max-height:var(--ck-accessibility-help-dialog-max-height);user-select:text;border:1px solid #0000;overflow:auto}.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content:focus{border:var(--ck-focus-ring);box-shadow:var(--ck-focus-outer-shadow), 0 0;outline:none}.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content *{white-space:normal}.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content .ck-label{display:none}.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content h3{font-size:1.2em;font-weight:bold}.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content h4{font-size:1em;font-weight:bold}.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content p,.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content h3,.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content h4,.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content table{margin:1em 0}.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content dl{border-top:1px solid var(--ck-accessibility-help-dialog-border-color);border-bottom:none;grid-template-columns:2fr 1fr;display:grid}.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content dl dt,.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content dl dd{border-bottom:1px solid var(--ck-accessibility-help-dialog-border-color);padding:0.4em 0}.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content dl dt{grid-column-start:1}.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content dl dd{text-align:right;grid-column-start:2}.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content kbd,.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content code{background:var(--ck-accessibility-help-dialog-code-background-color);vertical-align:middle;text-align:center;border-radius:2px;padding:0.4em;font-size:0.9em;line-height:1;display:inline-block}.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content code{font-family:monospace}.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content kbd{min-width:1.8em;box-shadow:0px 1px 1px var(--ck-accessibility-help-dialog-kbd-shadow-color);margin:0 1px}.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content kbd+kbd{margin-left:2px}.ck.ck-button,:where(a).ck.ck-button{--ck-button-background: var(--ck-color-button-default-background);--ck-button-hover-background: var(--ck-color-button-default-hover-background);--ck-button-active-background: var(--ck-color-button-default-active-background);--ck-button-disabled-background: var(--ck-color-button-default-disabled-background);background:var(--ck-button-background)}:is(.ck.ck-button, :where(a).ck.ck-button):not(.ck-disabled):hover{background:var(--ck-button-hover-background)}:is(.ck.ck-button, :where(a).ck.ck-button):not(.ck-disabled):active{background:var(--ck-button-active-background)}.ck.ck-button,:where(a).ck.ck-button{border-radius:var(--ck-rounded-corners-radius);white-space:nowrap;cursor:default;vertical-align:middle;padding:var(--ck-spacing-tiny);text-align:center;min-width:var(--ck-ui-component-min-height);min-height:var(--ck-ui-component-min-height);line-height:1;font-size:inherit;-webkit-appearance:none;-webkit-user-select:none;user-select:none;border:1px solid #0000;align-items:center;transition:box-shadow 0.2s ease-in-out, border 0.2s ease-in-out;display:inline-flex;position:relative}@media (prefers-reduced-motion:reduce){.ck.ck-button,:where(a).ck.ck-button{transition:none}}:is(.ck.ck-button, :where(a).ck.ck-button):active,:is(.ck.ck-button, :where(a).ck.ck-button):focus{border:var(--ck-focus-ring);box-shadow:var(--ck-focus-outer-shadow), 0 0;outline:none}:is(.ck.ck-button, :where(a).ck.ck-button) .ck-button__icon use,:is(.ck.ck-button, :where(a).ck.ck-button) .ck-button__icon use *{color:inherit}:is(.ck.ck-button, :where(a).ck.ck-button) .ck-button__label{font-size:inherit;font-weight:inherit;color:inherit;cursor:inherit;vertical-align:middle}[dir="ltr"] :is(:is(.ck.ck-button, :where(a).ck.ck-button) .ck-button__label){text-align:left}[dir="rtl"] :is(:is(.ck.ck-button, :where(a).ck.ck-button) .ck-button__label){text-align:right}:is(.ck.ck-button, :where(a).ck.ck-button) .ck-button__label{display:none}:is(.ck.ck-button, :where(a).ck.ck-button) .ck-button__keystroke{color:inherit;opacity:0.5}[dir="ltr"] :is(:is(.ck.ck-button, :where(a).ck.ck-button) .ck-button__keystroke){margin-left:var(--ck-spacing-large)}[dir="rtl"] :is(:is(.ck.ck-button, :where(a).ck.ck-button) .ck-button__keystroke){margin-right:var(--ck-spacing-large)}:is(.ck.ck-button, :where(a).ck.ck-button).ck-disabled{background:var(--ck-button-disabled-background)}:is(.ck.ck-button, :where(a).ck.ck-button).ck-disabled:active,:is(.ck.ck-button, :where(a).ck.ck-button).ck-disabled:focus{box-shadow:var(--ck-focus-disabled-outer-shadow), 0 0}:is(.ck.ck-button, :where(a).ck.ck-button).ck-disabled .ck-button__icon,:is(.ck.ck-button, :where(a).ck.ck-button).ck-disabled .ck-button__label{opacity:var(--ck-disabled-opacity)}:is(.ck.ck-button, :where(a).ck.ck-button).ck-disabled .ck-button__keystroke{opacity:0.3}:is(.ck.ck-button, :where(a).ck.ck-button).ck-button_with-text{padding:var(--ck-spacing-tiny) var(--ck-spacing-standard)}[dir="ltr"] :is(:is(.ck.ck-button, :where(a).ck.ck-button).ck-button_with-text .ck-button__icon){margin-right:var(--ck-spacing-medium)}[dir="rtl"] :is(:is(.ck.ck-button, :where(a).ck.ck-button).ck-button_with-text .ck-button__icon){margin-left:var(--ck-spacing-medium)}:is(.ck.ck-button, :where(a).ck.ck-button).ck-button_with-text .ck-button__label{display:inline-block}:is(.ck.ck-button, :where(a).ck.ck-button).ck-button_with-keystroke .ck-button__label{flex-grow:1}:is(.ck.ck-button, :where(a).ck.ck-button).ck-on{--ck-button-background: var(--ck-color-button-on-background);--ck-button-hover-background: var(--ck-color-button-on-hover-background);--ck-button-active-background: var(--ck-color-button-on-active-background);--ck-button-disabled-background: var(--ck-color-button-on-disabled-background);color:var(--ck-color-button-on-color)}:is(.ck.ck-button, :where(a).ck.ck-button).ck-button-save{color:var(--ck-color-button-save)}:is(.ck.ck-button, :where(a).ck.ck-button).ck-button-cancel{color:var(--ck-color-button-cancel)}[dir="ltr"] :is(.ck.ck-button, :where(a).ck.ck-button){justify-content:left}[dir="rtl"] :is(.ck.ck-button, :where(a).ck.ck-button){justify-content:right}:is(.ck.ck-button, :where(a).ck.ck-button):not(.ck-button_with-text){justify-content:center}.ck.ck-button-action,a.ck.ck-button-action{--ck-button-background: var(--ck-color-button-action-background);--ck-button-hover-background: var(--ck-color-button-action-hover-background);--ck-button-active-background: var(--ck-color-button-action-active-background);--ck-button-disabled-background: var(--ck-color-button-action-disabled-background);color:var(--ck-color-button-action-text)}.ck.ck-button-bold,a.ck.ck-button-bold{font-weight:bold}:root{--ck-switch-button-toggle-width: 2.61538em;--ck-switch-button-toggle-inner-size: calc(1.07692em + 1px);--ck-switch-button-translation: calc(var(--ck-switch-button-toggle-width) - + */:root{--skeleton-start-color: #e1e7ec;--skeleton-stop-color: #cfd8dc}.ibo-panel.ibo-is-selectable:hover .ibo-panel--body::after{font-family:"Font Awesome 5 Free";font-weight:400;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.dataTables_scrollHead thead tr th.sorting::after,.selectize-input .attribute-set-item.item-add::before,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active .attribute-set-item.item-add::before,.selectize-input .attribute-set-item.item-remove::before,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active .attribute-set-item.item-remove::before,.ibo-breadcrumbs--item:not(:last-child)::after,.ibo-breadcrumbs--previous-items-list-toggler:not(:last-child)::after,.ibo-panel.ibo-is-selectable .ibo-panel--body::after,.ibo-panel.ibo-is-selected .ibo-panel--body::after,.ibo-prop--apply.ui-state-error:after,.ibo-sort-order::after,.ibo-dashboard--slider:before,.ibo-dashboard--slider:after,.ibo-bulk--bulk-modify--incompatible-attribute:before,.ibo-linked-set--bulk-tooltip-info:before,.ibo-tab-container--tab-header.ibo-drag-in>a::after,.ibo-drag-in.ibo-tab-container--extra-tabs-container>a::after,.collapsable-options [data-role="setup-collapsable-options--toggler"]::before,#params_summary div.closed .title::before,#params_summary div:not(.closed) .title::before{font-family:"Font Awesome 5 Free";font-weight:900;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.common-is-fullwidth{width:100%}.common-font-size-50{font-size:0.83rem}.common-font-size-100{font-size:1rem}.common-font-size-150{font-size:1.17rem}.common-font-size-200{font-size:1.33rem}.common-font-size-250{font-size:1.5rem}.common-font-size-300{font-size:1.67rem}.common-font-size-350{font-size:1.83rem}.common-font-size-400{font-size:2rem}.common-font-size-450{font-size:2.5rem}.common-font-size-500{font-size:3rem}.common-font-size-550{font-size:4rem}.common-font-weight-100{font-weight:100}.common-font-weight-200{font-weight:200}.common-font-weight-300{font-weight:300}.common-font-weight-400{font-weight:400}.common-font-weight-500{font-weight:500}.common-font-weight-600{font-weight:600}.common-font-weight-700{font-weight:700}.common-font-weight-800{font-weight:800}.common-font-weight-900{font-weight:900}.common-font-weight-950{font-weight:950}.common-font-ral-nor-50{font-size:0.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-nor-100{font-size:1rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-nor-150{font-size:1.17rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-nor-200{font-size:1.33rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-nor-250{font-size:1.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-nor-300{font-size:1.67rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-nor-350{font-size:1.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-nor-400{font-size:2rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-nor-450{font-size:2.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-nor-500{font-size:3rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-nor-550{font-size:4rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-med-50{font-size:0.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-med-100{font-size:1rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-med-150{font-size:1.17rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-med-200{font-size:1.33rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-med-250{font-size:1.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-med-300{font-size:1.67rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-med-350{font-size:1.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-med-400{font-size:2rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-med-450{font-size:2.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-med-500{font-size:3rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-med-550{font-size:4rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-bol-50{font-size:0.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-bol-100{font-size:1rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-bol-150{font-size:1.17rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-bol-200{font-size:1.33rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-bol-250{font-size:1.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-bol-300{font-size:1.67rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-bol-350{font-size:1.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-bol-400{font-size:2rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-bol-450{font-size:2.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-bol-500{font-size:3rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-bol-550{font-size:4rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-sembol-50{font-size:0.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-sembol-100{font-size:1rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-sembol-150{font-size:1.17rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-sembol-200{font-size:1.33rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-sembol-250{font-size:1.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-sembol-300{font-size:1.67rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-sembol-350{font-size:1.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-sembol-400{font-size:2rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-sembol-450{font-size:2.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-sembol-500{font-size:3rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-sembol-550{font-size:4rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-ita-50{font-size:0.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-ita-100{font-size:1rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-ita-150{font-size:1.17rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-ita-200{font-size:1.33rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-ita-250{font-size:1.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-ita-300{font-size:1.67rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-ita-350{font-size:1.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-ita-400{font-size:2rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-ita-450{font-size:2.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-ita-500{font-size:3rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-ral-ita-550{font-size:4rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.common-font-code-50{font-size:0.83rem;font-family:monospace;font-weight:400}.common-font-code-100{font-size:1rem;font-family:monospace;font-weight:400}.common-font-code-150{font-size:1.17rem;font-family:monospace;font-weight:400}.common-font-code-200{font-size:1.33rem;font-family:monospace;font-weight:400}.common-font-code-250{font-size:1.5rem;font-family:monospace;font-weight:400}.common-font-code-300{font-size:1.67rem;font-family:monospace;font-weight:400}.common-font-code-350{font-size:1.83rem;font-family:monospace;font-weight:400}.common-font-code-400{font-size:2rem;font-family:monospace;font-weight:400}.common-font-code-450{font-size:2.5rem;font-family:monospace;font-weight:400}.common-font-code-500{font-size:3rem;font-family:monospace;font-weight:400}.common-font-code-550{font-size:4rem;font-family:monospace;font-weight:400}@font-face{font-family:Raleway;font-weight:100;font-style:normal;font-display:swap;src:local("Raleway Thin"), url("../node_modules/@fontsource/raleway/files/raleway-all-100-normal.woff") format("woff")}@font-face{font-family:Raleway;font-weight:100;font-style:italic;font-display:swap;src:local("Raleway Thin"), url("../node_modules/@fontsource/raleway/files/raleway-all-100-italic.woff") format("woff")}@font-face{font-family:Raleway;font-weight:200;font-style:normal;font-display:swap;src:local("Raleway ExtraLight"), url("../node_modules/@fontsource/raleway/files/raleway-all-200-normal.woff") format("woff")}@font-face{font-family:Raleway;font-weight:200;font-style:italic;font-display:swap;src:local("Raleway ExtraLight"), url("../node_modules/@fontsource/raleway/files/raleway-all-200-italic.woff") format("woff")}@font-face{font-family:Raleway;font-weight:300;font-style:normal;font-display:swap;src:local("Raleway Light"), url("../node_modules/@fontsource/raleway/files/raleway-all-300-normal.woff") format("woff")}@font-face{font-family:Raleway;font-weight:300;font-style:italic;font-display:swap;src:local("Raleway Light"), url("../node_modules/@fontsource/raleway/files/raleway-all-300-italic.woff") format("woff")}@font-face{font-family:Raleway;font-weight:400;font-style:normal;font-display:swap;src:local("Raleway"), url("../node_modules/@fontsource/raleway/files/raleway-all-400-normal.woff") format("woff")}@font-face{font-family:Raleway;font-weight:400;font-style:italic;font-display:swap;src:local("Raleway"), url("../node_modules/@fontsource/raleway/files/raleway-all-400-italic.woff") format("woff")}@font-face{font-family:Raleway;font-weight:500;font-style:normal;font-display:swap;src:local("Raleway Medium"), url("../node_modules/@fontsource/raleway/files/raleway-all-500-normal.woff") format("woff")}@font-face{font-family:Raleway;font-weight:500;font-style:italic;font-display:swap;src:local("Raleway Medium"), url("../node_modules/@fontsource/raleway/files/raleway-all-500-italic.woff") format("woff")}@font-face{font-family:Raleway;font-weight:600;font-style:normal;font-display:swap;src:local("Raleway SemiBold"), url("../node_modules/@fontsource/raleway/files/raleway-all-600-normal.woff") format("woff")}@font-face{font-family:Raleway;font-weight:600;font-style:italic;font-display:swap;src:local("Raleway SemiBold"), url("../node_modules/@fontsource/raleway/files/raleway-all-600-italic.woff") format("woff")}@font-face{font-family:Raleway;font-weight:700;font-style:normal;font-display:swap;src:local("Raleway"), url("../node_modules/@fontsource/raleway/files/raleway-all-700-normal.woff") format("woff")}@font-face{font-family:Raleway;font-weight:700;font-style:italic;font-display:swap;src:local("Raleway"), url("../node_modules/@fontsource/raleway/files/raleway-all-700-italic.woff") format("woff")}@font-face{font-family:Raleway;font-weight:800;font-style:normal;font-display:swap;src:local("Raleway ExtraBold"), url("../node_modules/@fontsource/raleway/files/raleway-all-800-normal.woff") format("woff")}@font-face{font-family:Raleway;font-weight:800;font-style:italic;font-display:swap;src:local("Raleway ExtraBold"), url("../node_modules/@fontsource/raleway/files/raleway-all-800-italic.woff") format("woff")}@font-face{font-family:Raleway;font-weight:900;font-style:normal;font-display:swap;src:local("Raleway Black"), url("../node_modules/@fontsource/raleway/files/raleway-all-900-normal.woff") format("woff")}@font-face{font-family:Raleway;font-weight:900;font-style:italic;font-display:swap;src:local("Raleway Black"), url("../node_modules/@fontsource/raleway/files/raleway-all-900-italic.woff") format("woff")}:root{--ibo-color-white-100: white;--ibo-color-white-200: #f2f2f2;--ibo-color-transparent: rgba(255, 255, 255, 0);--ibo-color-grey-50: #fcfcfd;--ibo-color-grey-100: #f8f9fa;--ibo-color-grey-200: #e1e7ec;--ibo-color-grey-300: #d5dde5;--ibo-color-grey-400: #ccd4db;--ibo-color-grey-500: #aebecd;--ibo-color-grey-600: #929fb1;--ibo-color-grey-700: #6e7a8a;--ibo-color-grey-800: #404b5a;--ibo-color-grey-900: #212934;--ibo-color-grey-950: #141a22;--ibo-color-blue-grey-50: #f1f5f8;--ibo-color-blue-grey-100: #cfd8dc;--ibo-color-blue-grey-200: #b0bec5;--ibo-color-blue-grey-300: #90a4ae;--ibo-color-blue-grey-400: #78909c;--ibo-color-blue-grey-500: #607d8b;--ibo-color-blue-grey-600: #546e7a;--ibo-color-blue-grey-700: #455a64;--ibo-color-blue-grey-800: #37474f;--ibo-color-blue-grey-900: #263238;--ibo-color-blue-grey-950: #1b2428;--ibo-color-blue-100: #ebf8ff;--ibo-color-blue-200: #bee3f8;--ibo-color-blue-300: #90cef4;--ibo-color-blue-400: #63b4ed;--ibo-color-blue-500: #429ae1;--ibo-color-blue-600: #3182ce;--ibo-color-blue-700: #2b6bb0;--ibo-color-blue-800: #2c5382;--ibo-color-blue-900: #2a4265;--ibo-color-blue-950: #253750;--ibo-color-cyan-100: #c9eef2;--ibo-color-cyan-200: #80deea;--ibo-color-cyan-300: #4dd0e1;--ibo-color-cyan-400: #26c5da;--ibo-color-cyan-500: #00bbd4;--ibo-color-cyan-600: #00aac1;--ibo-color-cyan-700: #0096a7;--ibo-color-cyan-800: #00838f;--ibo-color-cyan-900: #006164;--ibo-color-cyan-950: #003636;--ibo-color-green-100: #dcedc8;--ibo-color-green-200: #c5e1a5;--ibo-color-green-300: #aed581;--ibo-color-green-400: #9ccc65;--ibo-color-green-500: #8ac34a;--ibo-color-green-600: #7cb342;--ibo-color-green-700: #689f38;--ibo-color-green-800: #558b2f;--ibo-color-green-900: #33691e;--ibo-color-green-950: #235816;--ibo-color-orange-100: floralwhite;--ibo-color-orange-200: #feebc8;--ibo-color-orange-300: #fbd38d;--ibo-color-orange-400: #f6ae55;--ibo-color-orange-500: #ea7d1e;--ibo-color-orange-600: #dd6c20;--ibo-color-orange-700: #c05621;--ibo-color-orange-800: #9c4221;--ibo-color-orange-900: #7b341e;--ibo-color-orange-950: #572819;--ibo-color-red-100: #fce8e8;--ibo-color-red-200: #fed7d7;--ibo-color-red-300: #feb2b2;--ibo-color-red-400: #fc8181;--ibo-color-red-500: #f56565;--ibo-color-red-600: #e53e3e;--ibo-color-red-700: #c53030;--ibo-color-red-800: #9b2c2c;--ibo-color-red-900: #742a2a;--ibo-color-red-950: #491d1d;--ibo-color-pink-100: #fff5f7;--ibo-color-pink-200: #fed7e2;--ibo-color-pink-300: #fbb6ce;--ibo-color-pink-400: #f688b4;--ibo-color-pink-500: #ed64a6;--ibo-color-pink-600: #d53f8c;--ibo-color-pink-700: #b83280;--ibo-color-pink-800: #97266d;--ibo-color-pink-900: #702459;--ibo-color-pink-950: #511a40;--ibo-color-yellow-100: ivory;--ibo-color-yellow-200: #fefcbf;--ibo-color-yellow-300: #faf089;--ibo-color-yellow-400: #f6e05e;--ibo-color-yellow-500: #ecc94b;--ibo-color-yellow-600: #d69e2e;--ibo-color-yellow-700: #b7791f;--ibo-color-yellow-800: #975a16;--ibo-color-yellow-900: #744210;--ibo-color-yellow-950: #4e2a09;--ibo-color-purple-100: #ede9fe;--ibo-color-purple-200: #ddd6fe;--ibo-color-purple-300: #c4b5fd;--ibo-color-purple-400: #a78bfa;--ibo-color-purple-500: #8b5cf6;--ibo-color-purple-600: #7c3aed;--ibo-color-purple-700: #6d28d9;--ibo-color-purple-800: #5b21b6;--ibo-color-purple-900: #4c1d95;--ibo-color-purple-950: #371371}:root{--ibo-color-primary-100: floralwhite;--ibo-color-primary-200: #feebc8;--ibo-color-primary-300: #fbd38d;--ibo-color-primary-400: #f6ae55;--ibo-color-primary-500: #ea7d1e;--ibo-color-primary-600: #dd6c20;--ibo-color-primary-700: #c05621;--ibo-color-primary-800: #9c4221;--ibo-color-primary-900: #7b341e;--ibo-color-primary-950: #572819;--ibo-color-secondary-100: #f8f9fa;--ibo-color-secondary-200: #e1e7ec;--ibo-color-secondary-300: #d5dde5;--ibo-color-secondary-400: #ccd4db;--ibo-color-secondary-500: #aebecd;--ibo-color-secondary-600: #929fb1;--ibo-color-secondary-700: #6e7a8a;--ibo-color-secondary-800: #404b5a;--ibo-color-secondary-900: #212934;--ibo-color-secondary-950: #141a22;--ibo-color-information-100: #ebf8ff;--ibo-color-information-200: #bee3f8;--ibo-color-information-300: #90cef4;--ibo-color-information-400: #63b4ed;--ibo-color-information-500: #429ae1;--ibo-color-information-600: #3182ce;--ibo-color-information-700: #2b6bb0;--ibo-color-information-800: #2c5382;--ibo-color-information-900: #2a4265;--ibo-color-information-950: #253750;--ibo-color-success-100: #dcedc8;--ibo-color-success-200: #c5e1a5;--ibo-color-success-300: #aed581;--ibo-color-success-400: #9ccc65;--ibo-color-success-500: #8ac34a;--ibo-color-success-600: #7cb342;--ibo-color-success-700: #689f38;--ibo-color-success-800: #558b2f;--ibo-color-success-900: #33691e;--ibo-color-success-950: #235816;--ibo-color-warning-100: floralwhite;--ibo-color-warning-200: #feebc8;--ibo-color-warning-300: #fbd38d;--ibo-color-warning-400: #f6ae55;--ibo-color-warning-500: #ea7d1e;--ibo-color-warning-600: #dd6c20;--ibo-color-warning-700: #c05621;--ibo-color-warning-800: #9c4221;--ibo-color-warning-900: #7b341e;--ibo-color-warning-950: #572819;--ibo-color-danger-100: #fce8e8;--ibo-color-danger-200: #fed7d7;--ibo-color-danger-300: #feb2b2;--ibo-color-danger-400: #fc8181;--ibo-color-danger-500: #f56565;--ibo-color-danger-600: #e53e3e;--ibo-color-danger-700: #c53030;--ibo-color-danger-800: #9b2c2c;--ibo-color-danger-900: #742a2a;--ibo-color-danger-950: #491d1d;--ibo-color-error-100: #fce8e8;--ibo-color-error-200: #fed7d7;--ibo-color-error-300: #feb2b2;--ibo-color-error-400: #fc8181;--ibo-color-error-500: #f56565;--ibo-color-error-600: #e53e3e;--ibo-color-error-700: #c53030;--ibo-color-error-800: #9b2c2c;--ibo-color-error-900: #742a2a;--ibo-color-error-950: #491d1d;--ibo-caselog-color-highlight-1: #689f38;--ibo-caselog-color-highlight-2: #b83280;--ibo-caselog-color-highlight-3: #f6ae55;--ibo-caselog-color-highlight-4: #3182ce;--ibo-caselog-color-highlight-5: #80deea}:root{--ibo-lifecycle-new-state-primary-color: #2c5382;--ibo-lifecycle-new-state-secondary-color: white;--ibo-lifecycle-neutral-state-primary-color: #2c5382;--ibo-lifecycle-neutral-state-secondary-color: white;--ibo-lifecycle-waiting-state-primary-color: #f6ae55;--ibo-lifecycle-waiting-state-secondary-color: white;--ibo-lifecycle-success-state-primary-color: #689f38;--ibo-lifecycle-success-state-secondary-color: white;--ibo-lifecycle-failure-state-primary-color: #b83280;--ibo-lifecycle-failure-state-secondary-color: white;--ibo-lifecycle-frozen-state-primary-color: #e1e7ec;--ibo-lifecycle-frozen-state-secondary-color: #6e7a8a;--ibo-lifecycle-active-state-primary-color: #689f38;--ibo-lifecycle-active-state-secondary-color: white;--ibo-lifecycle-inactive-state-primary-color: #f6ae55;--ibo-lifecycle-inactive-state-secondary-color: white}:root{--skeleton-start-color: #e1e7ec;--skeleton-stop-color: #cfd8dc}:root{--ibo-border-radius-100: 1px;--ibo-border-radius-300: 3px;--ibo-border-radius-500: 5px;--ibo-border-radius-700: 10px;--ibo-border-radius-900: 16px;--ibo-border-radius-full: 100%}:root{--ibo-depression-100: inset 0 1px 1px 0 rgba(0, 0, 0, 0.15)}:root{--ibo-elevation-100: 0 1px 2px rgba(0, 0, 0, 0.25), 0 1px 3px rgba(0, 0, 0, 0.12);--ibo-elevation-200: 0 2px 4px rgba(0, 0, 0, 0.12), 0 3px 6px rgba(0, 0, 0, 0.15);--ibo-elevation-300: 0 3px 6px rgba(0, 0, 0, 0.1), 0 10px 20px rgba(0, 0, 0, 0.15);--ibo-elevation-400: 0 5px 10px rgba(0, 0, 0, 0.05), 0 15px 25px rgba(0, 0, 0, 0.15);--ibo-elevation-500: 0 20px 40px rgba(0, 0, 0, 0.2)}:root{--ibo-size-0: 0;--ibo-size-50: 2px;--ibo-size-100: 4px;--ibo-size-150: 8px;--ibo-size-200: 12px;--ibo-size-250: 16px;--ibo-size-300: 24px;--ibo-size-350: 32px;--ibo-size-400: 48px;--ibo-size-450: 64px;--ibo-size-500: 96px;--ibo-size-550: 128px;--ibo-size-600: 192px;--ibo-size-650: 256px;--ibo-size-700: 384px;--ibo-size-750: 512px;--ibo-size-800: 640px;--ibo-size-850: 768px;--ibo-size-900: 896px}:root{--ibo-spacing-0: 0;--ibo-spacing-100: 2px;--ibo-spacing-200: 4px;--ibo-spacing-300: 8px;--ibo-spacing-400: 12px;--ibo-spacing-500: 16px;--ibo-spacing-600: 24px;--ibo-spacing-700: 32px;--ibo-spacing-800: 48px;--ibo-spacing-900: 64px;--ibo-spacing-950: 96px}:root{--ibo-font-size-50: 0.83rem;--ibo-font-size-100: 1rem;--ibo-font-size-150: 1.17rem;--ibo-font-size-200: 1.33rem;--ibo-font-size-250: 1.5rem;--ibo-font-size-300: 1.67rem;--ibo-font-size-350: 1.83rem;--ibo-font-size-400: 2rem;--ibo-font-size-450: 2.5rem;--ibo-font-size-500: 3rem;--ibo-font-size-550: 4rem}:root{--ibo-font-weight-100: 100;--ibo-font-weight-200: 200;--ibo-font-weight-300: 300;--ibo-font-weight-400: 400;--ibo-font-weight-500: 500;--ibo-font-weight-600: 600;--ibo-font-weight-700: 700;--ibo-font-weight-800: 800;--ibo-font-weight-900: 900;--ibo-font-weight-950: 950}:root{--ibo-font-family-base: Raleway;--ibo-font-family-monospace: monospace;--ibo-font-family-code: monospace}#ibo-setup-licenses--components-list{border-radius:3px}.ibo-welcome-popup--stack-item{border-radius:4px}.ibo-datatable .ibo-field-badge::before{border-radius:100%}.ibo-text.ibo-is-primary{color:#9c4221}.ibo-text.ibo-is-secondary,.ui-dialog .ibo-text.ui-button,.ibo-text.ui-datepicker-current,.ibo-text.ui-datepicker-close{color:#404b5a}.ibo-text.ibo-is-neutral,.ui-dialog .ibo-text.ui-button.ui-dialog-titlebar-close{color:#404b5a}.ibo-text.ibo-is-information{color:#2c5382}.ibo-text.ibo-is-success{color:#558b2f}.ibo-text.ibo-is-failure{color:#9b2c2c}.ibo-text.ibo-is-warning{color:#9c4221}.ibo-text.ibo-is-danger{color:#9b2c2c}.ibo-text.ibo-is-grey{color:#404b5a}.ibo-text.ibo-is-blue-grey{color:#37474f}.ibo-text.ibo-is-blue{color:#2c5382}.ibo-text.ibo-is-cyan{color:#00838f}.ibo-text.ibo-is-green{color:#558b2f}.ibo-text.ibo-is-orange{color:#9c4221}.ibo-text.ibo-is-red{color:#9b2c2c}.ibo-text.ibo-is-pink{color:#97266d}.ibo-class-icon.ibo-is-small{width:32px;min-width:32px;max-height:32px}.ibo-class-icon.ibo-is-medium{width:48px;min-width:48px;max-height:48px}.ibo-class-icon.ibo-is-large{width:64px;min-width:64px;max-height:64px}.ibo-activity-panel--tab-title-decoration{box-shadow:inset 0 1px 1px 0 rgba(0, 0, 0, 0.15)}.ibo-top-bar,.ibo-tab-container--extra-tabs-list{box-shadow:0 1px 2px rgba(0, 0, 0, 0.25), 0 1px 3px rgba(0, 0, 0, 0.12)}.ibo-breadcrumbs--previous-items-list,.ibo-quick-create--input.selectize-control.single .selectize-dropdown,.ibo-popover-menu,.ui-menu,.ui-multiselect-menu,.ibo-input-select-icon--menu,.graph_config .toolkit_menu.graph>ul>li ul,.ibo-activity-panel--filter-options{box-shadow:0 3px 6px rgba(0, 0, 0, 0.1), 0 10px 20px rgba(0, 0, 0, 0.15)}html.ibo-has-fullscreen-descendant{position:fixed !important;width:0 !important;height:0 !important}body.ibo-has-fullscreen-descendant{width:0 !important;height:0 !important;overflow:hidden !important}.ibo-has-fullscreen-descendant{position:static !important;overflow:visible !important;z-index:1050 !important}.ibo-is-fullscreen{position:absolute;top:0 !important;left:0 !important;margin:0 !important;padding:0 !important;width:100vw;height:100vh;overflow:auto;z-index:1050}.ibo-sticky-sentinel{position:absolute;left:0;right:0;visibility:hidden}.ibo-sticky-sentinel-top{top:0;height:0}.ibo-sticky-sentinel-bottom{bottom:0;height:0}:root{--ibo-hyperlink-color: #c05621;--ibo-hyperlink-text-decoration: none;--ibo-hyperlink-color--on-hover: #9c4221;--ibo-hyperlink-text-decoration--on-hover: none;--ibo-hyperlink-color--on-active: #7b341e;--ibo-hyperlink-text-decoration--on-active: none}.ibo-text-truncated-with-ellipsis,.ui-dialog .ui-dialog-title,.ibo-button--label,.ibo-breadcrumbs--item-label,.ibo-quick-create--compartment-element,.ibo-quick-create--compartment-results--element>.option,.ibo-global-search--compartment-element,.ibo-dashlet-badge--action-list-label,.ibo-input-select--autocomplete-item-txt,.attribute-set .attribute-set-item,.selectize-control.multi .selectize-input.ibo-input-set .attribute-set-item,.selectize-control.multi .ibo-quick-create--input.selectize-control.single .ibo-input-set.selectize-input.input-active .attribute-set-item,.ibo-quick-create--input.selectize-control.single .selectize-control.multi .ibo-input-set.selectize-input.input-active .attribute-set-item,.attribute-set .attribute-set-item>*,.selectize-control.multi .selectize-input.ibo-input-set .attribute-set-item>*,.selectize-control.multi .ibo-quick-create--input.selectize-control.single .ibo-input-set.selectize-input.input-active .attribute-set-item>*,.ibo-quick-create--input.selectize-control.single .selectize-control.multi .ibo-input-set.selectize-input.input-active .attribute-set-item>*,.ibo-navigation-menu--menu-group-title,.ibo-top-bar--toolbar-dashboard-title,.ibo-tab-container--tab-toggler,.ibo-tab-container--extra-tabs-list-toggler,.ibo-tab-container--tab-toggler-label,.ibo-tab-container--extra-tab-toggler,.ibo-object-details>.ibo-panel--header .ibo-panel--subtitle,.ibo-object-details>.ibo-object-summary--header .ibo-panel--subtitle,.ibo-activity-panel--tab-title-text,.ibo-activity-panel--filter-option,.ibo-welcome-popup--stack-item-title{white-space:nowrap;overflow-x:hidden;text-overflow:ellipsis}.dataTables_paginate a.paginate_button,.ibo-dashlet-badge--action-list:hover,.ibo-dashlet-badge--action-list:active,.ibo-field--fullscreen-toggler,.ibo-input-select--action-buttons a,.search_form_handler a,.ibo-navigation-menu--menu-filter-clear,.ibo-navigation-menu--menu-filter-hint-close,.ibo-tab-container--tab-toggler,.ibo-tab-container--extra-tabs-list-toggler,.ibo-activity-panel--load-entries-button,.ibo-welcome-popup--stack-item-title{color:inherit}.dataTables_paginate a.paginate_button:hover,.ibo-dashlet-badge--action-list:hover,.ibo-dashlet-badge--action-list:active:hover,.ibo-field--fullscreen-toggler:hover,.ibo-input-select--action-buttons a:hover,.search_form_handler a:hover,.ibo-navigation-menu--menu-filter-clear:hover,.ibo-navigation-menu--menu-filter-hint-close:hover,.ibo-tab-container--tab-toggler:hover,.ibo-tab-container--extra-tabs-list-toggler:hover,.ibo-activity-panel--load-entries-button:hover,.ibo-welcome-popup--stack-item-title:hover,.dataTables_paginate a.paginate_button:active,.ibo-dashlet-badge--action-list:hover:active,.ibo-dashlet-badge--action-list:active,.ibo-field--fullscreen-toggler:active,.ibo-input-select--action-buttons a:active,.search_form_handler a:active,.ibo-navigation-menu--menu-filter-clear:active,.ibo-navigation-menu--menu-filter-hint-close:active,.ibo-tab-container--tab-toggler:active,.ibo-tab-container--extra-tabs-list-toggler:active,.ibo-activity-panel--load-entries-button:active,.ibo-welcome-popup--stack-item-title:active{color:inherit}.ibo-navigation-menu--notifications-item .ibo-navigation-menu--notifications--item--content a{color:#c05621;text-decoration:none}.ibo-navigation-menu--notifications-item .ibo-navigation-menu--notifications--item--content a:hover{color:#9c4221;text-decoration:none}.ibo-navigation-menu--notifications-item .ibo-navigation-menu--notifications--item--content a:active{color:#7b341e;text-decoration:none}.ibo-is-broken-hyperlink{text-decoration:line-through;cursor:help}.ibo-is-disabled{cursor:not-allowed !important}.ibo-has-description::after{content:"🛈";padding-left:4px;vertical-align:top;cursor:pointer;color:#929fb1;font-size:0.7em}.ibo-is-code{background-color:#f2f2f2;padding:1.25rem 1.5rem}.ibo-is-html-content{}.ibo-is-html-content table{border-collapse:separate;border-spacing:2px}.ibo-is-html-content>code,.ibo-is-html-content code:not(.hljs){color:inherit}.ibo-is-html-content p{margin-top:0.25em;margin-bottom:0.25em}.ibo-is-html-content figure{display:inline-block;margin-left:2em !important;margin-right:2em !important}.ibo-is-html-content figure:not(:last-child){margin-bottom:2em !important}.ibo-is-html-content figure:not(:first-child){margin-top:2em !important}.ibo-is-fullwidth{width:100%}.ibo-welcome-popup--stack-item-icon,.ibo-panel--header-left,.ibo-panel--icon,.ibo-dashlet-header-static--icon-container,.ibo-input-image--image-view,.ibo-input-select--autocomplete-item-image,.ibo-pill,.ibo-title--icon,.ibo-datatable--toolbar-left,.ibo-datatable--toolbar-right,.ibo-field--fullscreen-toggler,.ibo-navigation-menu--bottom-part,.ibo-navigation-menu--user-info,.ibo-navigation-menu--user-info .ibo-navigation-menu--user-picture,.ibo-tab-container--tab-toggler,.ibo-tab-container--extra-tabs-list-toggler,.ibo-object-details--status-dot,.ibo-activity-panel--tab-title,.ibo-activity-panel--tab-toolbar-actions,.ibo-activity-panel--tab-toolbar-action,.ibo-activity-panel--body--placeholder-image,.ibo-activity-panel--body--placeholder-hint,.ibo-activity-panel--closed-cover,.ibo-caselog-entry-form--lock-icon,.ibo-activity-entry--medallion,.ibo-activity-panel--load-more-entries-container,.ibo-activity-panel--load-entries-button,.ibo-notifications--view-all--empty{display:flex;justify-content:center;align-items:center}.dataTables_paginate,.ibo-dashlet-badge--action-list,.ibo-input,.ui-autocomplete-input,.ui-multiselect,.dataTables_length select,.ui_tpicker_hour_slider>select,.ui_tpicker_minute_slider>select,.ui_tpicker_second_slider>select,select.ibo-input-select-placeholder,.ibo-datatableconfig--attributes-panel--per-page--input,.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content input[type="text"],.search_form_handler .sf_filter .sff_input_wrapper input[type="text"],.ibo-toolbar.ibo-toolbar--button,.ibo-activity-panel--tab-toolbar-left-actions,.ibo-activity-panel--tab-toolbar-middle-actions,.ibo-activity-panel--tab-toolbar-right-actions,.ibo-activity-panel--filter-option,.ibo-activity-panel--entry-forms-confirmation-preference,.ibo-caselog-entry-form--lock-indicator,.ibo-caselog-entry-form--action-buttons--main-actions,.ibo-welcome-popup--stack-item,#ibo_setup_container .ibo-title,#ibo_setup_container .ibo-setup--body .ibo-setup--button-bar,.ibo-setup--button-bar{display:flex;align-items:center}.ibo-dashlet-badge--action-create,.ibo-title,.ibo-title--subtitle,.ibo-object-details--status,.ibo-activity-panel--add-caselog-entry-button{display:flex;align-items:baseline}.ibo-breadcrumbs,.ibo-quick-create,.ibo-quick-create--head,.ibo-global-search,.ibo-global-search--head,.ibo-top-bar,.ibo-top-bar--quick-actions,.ibo-top-bar--toolbar,.ibo-top-bar--toolbar-dashboard-menu-toggler,.ibo-tab-container--tabs-list,.ibo-tab-container--tab-header,.ibo-tab-container--extra-tabs-container,.ibo-dashboard--top-bar,.ibo-welcome-popup--dialog{display:flex;align-items:stretch}.ibo-font-size-50,.ibo-field--fullscreen-toggler,.ibo-activity-panel--tab-title-draft-indicator,.ibo-activity-entry--sub-information{font-size:0.83rem}.ibo-font-size-100,.dataTables_paginate a.paginate_button,.selectize-add-option,.ibo-quick-create--drawer,.ibo-global-search--drawer,.ibo-dashlet-header-dynamic--label,.ibo-datatable--toolbar,.object-ref-icon.text_decoration,.object-ref-icon-disabled.text_decoration,.ibo-criterion-area,.ibo-dashboard-editor--properties table td .ibo-field,.ibo-dashboard-editor--properties table th .ibo-field,.ibo-dashboard--available-dashlets table td .ibo-field,.ibo-dashboard--available-dashlets table th .ibo-field,.ibo-dashlet--properties table td .ibo-field,.ibo-dashlet--properties table th .ibo-field,.ibo-caselog-list .ibo-collapsible-section .ibo-collapsible-section--header .ibo-collapsible-section--title,.ibo-caselog-list .ibo-collapsible-section .ibo-collapsible-section--body{font-size:1rem}.ibo-font-size-150,.ibo-alert,.ibo-breadcrumbs--item-icon,.ibo-panel--subtitle,.ibo-panel--body,.ibo-dashlet-badge--action-create,.ibo-spinner.ibo-is-small>.ibo-spinner--description,.ibo-prop-header,.ibo-field,.sf_results_placeholder,.ibo-input-file-select--container .ibo-input-file-select .ibo-input-file-select--file-name,.ibo-tab-container--tabs-list,.ibo-dashboard-editor--properties-subtitle,.ibo-dashboard--available-dashlet--title,.ibo-dashlet--properties--title,.ibo-activity-entry--medallion,.ibo-alert--body .ibo-collapsible-section .ibo-collapsible-section--header .ibo-collapsible-section--title,.ibo-alert--body .ibo-collapsible-section .ibo-collapsible-section--body{font-size:1.17rem}.ibo-font-size-200,.dataTables_paginate a.paginate_button.previous,.dataTables_paginate a.paginate_button.next{font-size:1.33rem}.ibo-font-size-250,.ibo-collapsible-section .ibo-collapsible-section--header .ibo-collapsible-section--title,.ibo-spinner.ibo-is-small>.ibo-spinner--icon,.ibo-spinner.ibo-is-medium>.ibo-spinner--description,.ibo-fieldset-legend,.ibo-dashboard-editor--properties-subtitle,.ibo-dashboard--available-dashlet--title,.ibo-dashlet--properties--title,legend,.ibo-top-bar--toolbar-dashboard-title,.ibo-tab-container--tab-container--label>span,.ibo-dashboard-editor--properties-title{font-size:1.5rem}.ibo-font-size-300,.ibo-title--for-object-details,.ibo-tab--temporary-remote-content--button{font-size:1.67rem}.ibo-font-size-350,.ibo-panel--title,.ibo-dashlet-header-static--body,.ibo-title-for-dashlet--title{font-size:1.83rem}.ibo-font-size-400,.ibo-spinner.ibo-is-large>.ibo-spinner--description{font-size:2rem}.ibo-font-size-450{font-size:2.5rem}.ibo-font-size-500,.ibo-spinner.ibo-is-medium>.ibo-spinner--icon{font-size:3rem}.ibo-font-size-550,.ibo-spinner.ibo-is-large>.ibo-spinner--icon{font-size:4rem}.ibo-font-weight-100{font-weight:100}.ibo-font-weight-200{font-weight:200}.ibo-font-weight-300{font-weight:300}.ibo-font-weight-400{font-weight:400}.ibo-font-weight-500{font-weight:500}.ibo-font-weight-600,.ibo-navigation-menu--notifications-show-all-multiple~.ibo-popover-menu .ibo-navigation-menu--notifications-show-all-multiple--counter,.ibo-navigation-menu--notifications-show-all-multiple~.ui-menu .ibo-navigation-menu--notifications-show-all-multiple--counter,.ibo-navigation-menu--notifications-show-all-multiple~.ui-multiselect-menu .ibo-navigation-menu--notifications-show-all-multiple--counter,.ibo-navigation-menu--notifications-show-all-multiple~.ibo-input-select-icon--menu .ibo-navigation-menu--notifications-show-all-multiple--counter,.graph_config .toolkit_menu.graph>ul>li .ibo-navigation-menu--notifications-show-all-multiple~ul .ibo-navigation-menu--notifications-show-all-multiple--counter,.ibo-dashlet-badge--body--tooltip-title,.ibo-field--label,.ibo-tab-container--extra-tab-toggler--tooltip-title{font-weight:600}.ibo-has-description::after,.ibo-font-weight-700,.ibo-alert .ibo-alert--title,.ibo-tab-container--tab-header.ui-tabs-active,.ui-tabs-active.ibo-tab-container--extra-tabs-container{font-weight:700}.ibo-font-weight-800{font-weight:800}.ibo-font-weight-900{font-weight:900}.ibo-font-weight-950{font-weight:950}.ibo-font-ral-nor-50,.ibo-navigation-menu--menu-filter-hotkey{font-size:0.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-nor-100,.ui-datepicker .ui-datepicker-title select,.ui-multiselect-checkboxes label,.ibo-input-select--autocomplete-item-txt,.ibo-datatableconfig--attributes-panel .ibo-panel--body,.ibo-navigation-menu--user-info .ibo-navigation-menu--user-organization,.ibo-linked-set--bulk-tooltip-info,.dataModelSchema text,.tooltipD3{font-size:1rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-nor-150,.ibo-input,.ui-autocomplete-input,.ui-multiselect,.dataTables_length select,.ui_tpicker_hour_slider>select,.ui_tpicker_minute_slider>select,.ui_tpicker_second_slider>select,select.ibo-input-select-placeholder,.ibo-datatableconfig--attributes-panel--per-page--input,.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content input[type="text"],.search_form_handler .sf_filter .sff_input_wrapper input[type="text"],.ibo-input-select.ibo-input-selectize input,.ibo-input-selectize.ui-multiselect input,.ui_tpicker_hour_slider>select.ibo-input-selectize input,.ui_tpicker_minute_slider>select.ibo-input-selectize input,.ui_tpicker_second_slider>select.ibo-input-selectize input,select.ibo-input-selectize.ibo-input-select-placeholder input,.ibo-title--subtitle,.ibo-navigation-menu--menu-nodes ul li>a,.ibo-navigation-menu--menu-nodes ul li>span,.ibo-navigation-menu--user-info .ibo-navigation-menu--user-notifications,.ibo-datamodel-viewer--details .ibo-panel--subtitle,.ibo-global-search--result--title{font-size:1.17rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-nor-200,.ibo-collapsible-section .ibo-collapsible-section--body,.ibo-navigation-menu--menu-group{font-size:1.33rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-nor-250,.ui-dialog-title,.ibo-navigation-menu--user-info .ibo-navigation-menu--user-welcome-message,#ibo_setup_container .ibo-setup--body .setup-content-title,#ibo_setup_container .ibo-setup--body h2,.setup-end-placeholder a{font-size:1.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-nor-300,.ibo-quick-create--input.selectize-control.single .selectize-input>input,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active>input,.ibo-quick-create--input.selectize-control.single .selectize-input>.item,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active>.item,.ibo-global-search--input,.ibo-global-search--input:hover,.ibo-global-search--input:focus,.ibo-global-search--input:active{font-size:1.67rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-nor-350,.ibo-navigation-menu--menu-nodes-title{font-size:1.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-nor-400,.ibo-quick-create--icon,.ibo-global-search--icon{font-size:2rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-nor-450{font-size:2.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-nor-500{font-size:3rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-nor-550{font-size:4rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-med-50,.ibo-badge{font-size:0.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-med-100,.dataTable th,.dataTable td,.ibo-breadcrumbs--item,.ibo-breadcrumbs--previous-items-list-toggler,.ibo-breadcrumbs--previous-item,.ibo-datatable[data-status="loading"] td,.ibo-extension-details--information--metadata,.ibo-extension-details--information--description,body{font-size:1rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-med-150,.ui-multiselect-checkboxes li,.ibo-extension-details--information--label,.ibo-welcome-popup--stack-item-title,.ibo-welcome-popup--message-description,.ibo-datamodel-viewer--breadcrumb{font-size:1.17rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-med-200{font-size:1.33rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-med-250,.ibo-dashlet-badge--action-list{font-size:1.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-med-300,.ibo-title--text{font-size:1.67rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-med-350{font-size:1.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-med-400,.ibo-datamodel-viewer--empty--text{font-size:2rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-med-450{font-size:2.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-med-500{font-size:3rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-med-550{font-size:4rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:500;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-bol-50,.ibo-navigation-menu--menu-filter-clear,.ibo-datamodel-viewer--icon--abstract:after{font-size:0.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-bol-100,.ui-multiselect-header ul,.ui-multiselect-checkboxes li.ui-multiselect-optgroup-label,.ibo-navigation-menu--menu-node-counter,#tooltipD3_top{font-size:1rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-bol-150,.ibo-object-summary--content--attributes--code,.ibo-alert.ibo-is-primary a,.ibo-alert.ibo-is-secondary a,.ui-dialog .ibo-alert.ui-button a,.ibo-alert.ui-datepicker-current a,.ibo-alert.ui-datepicker-close a,.ibo-alert.ibo-is-neutral a,.ui-dialog .ibo-alert.ui-button.ui-dialog-titlebar-close a,.ibo-toast.ibo-is-information a,.ibo-alert.ibo-is-information a,.ibo-toast.ibo-is-success a,.ibo-alert.ibo-is-success a,.ibo-alert.ibo-is-failure a,.ibo-toast.ibo-is-warning a,.ibo-alert.ibo-is-warning a,.ibo-toast.ibo-is-error a,.ibo-alert.ibo-is-danger a,.ibo-alert.ibo-is-grey a,.ibo-alert.ibo-is-blue-grey a,.ibo-alert.ibo-is-blue a,.ibo-alert.ibo-is-cyan a,.ibo-alert.ibo-is-green a,.ibo-alert.ibo-is-orange a,.ibo-alert.ibo-is-red a,.ibo-alert.ibo-is-pink a,.ibo-welcome-popup--message-title{font-size:1.17rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-bol-200,.ibo-dashlet-header-dynamic--count{font-size:1.33rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-bol-250,.ibo-dashboard--top-bar .ibo-dashboard--top-bar-title{font-size:1.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-bol-300{font-size:1.67rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-bol-350{font-size:1.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-bol-400{font-size:2rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-bol-450,.ibo-dashlet-badge--action-list-count{font-size:2.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-bol-500{font-size:3rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-bol-550{font-size:4rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:700;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-sembol-50{font-size:0.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-sembol-100,.dataTables_paginate a.paginate_button.current,.dataTables_scrollHead thead tr th,.ibo-button,.ui-dialog .ui-button,.ui-datepicker-current,.ui-datepicker-close,.ibo-datatable[data-status="loading"] th{font-size:1rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-sembol-150{font-size:1.17rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-sembol-200{font-size:1.33rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-sembol-250{font-size:1.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-sembol-300{font-size:1.67rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-sembol-350{font-size:1.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-sembol-400{font-size:2rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-sembol-450{font-size:2.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-sembol-500{font-size:3rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-sembol-550{font-size:4rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:600;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-ita-50,.ibo-navigation-menu--menu-filter-hint{font-size:0.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-ita-100,.ibo-quick-create--compartment--placeholder-hint,.ibo-global-search--compartment--placeholder-hint,.ibo-navigation-menu--menu--placeholder-hint,.ibo-activity-panel--body--placeholder-hint{font-size:1rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-ita-150{font-size:1.17rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-ita-200{font-size:1.33rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-ita-250{font-size:1.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-ita-300{font-size:1.67rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-ita-350{font-size:1.83rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-ita-400{font-size:2rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-ita-450{font-size:2.5rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-ita-500{font-size:3rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-ral-ita-550{font-size:4rem;font-family:"Raleway", "sans-serif", "system-ui";font-weight:400;font-style:italic;-webkit-font-feature-settings:"lnum";-moz-font-feature-settings:"lnum";font-feature-settings:"lnum"}.ibo-font-code-50{font-size:0.83rem;font-family:monospace;font-weight:400}.ibo-font-code-100,.ibo-datamodel-viewer--classname{font-size:1rem;font-family:monospace;font-weight:400}.ibo-is-code,.ibo-font-code-150,.ibo-input-text.ibo-is-code,textarea.ibo-is-code{font-size:1.17rem;font-family:monospace;font-weight:400}.ibo-font-code-200{font-size:1.33rem;font-family:monospace;font-weight:400}.ibo-font-code-250{font-size:1.5rem;font-family:monospace;font-weight:400}.ibo-font-code-300{font-size:1.67rem;font-family:monospace;font-weight:400}.ibo-font-code-350{font-size:1.83rem;font-family:monospace;font-weight:400}.ibo-font-code-400{font-size:2rem;font-family:monospace;font-weight:400}.ibo-font-code-450{font-size:2.5rem;font-family:monospace;font-weight:400}.ibo-font-code-500{font-size:3rem;font-family:monospace;font-weight:400}.ibo-font-code-550{font-size:4rem;font-family:monospace;font-weight:400}.ibo-add-margin-top-250{margin-top:12px}.ibo-welcome-popup--stack-item-icon{position:relative;border-radius:var(--ibo-border-radius-full);border:2px solid var(--ibo-color-grey-300);overflow:hidden}.ibo-welcome-popup--stack-item-icon>*{position:absolute;top:0;left:0;width:100%;height:100%;background-position:center;background-size:contain;background-color:var(--ibo-color-grey-500)}.ibo-is-visible{display:inherit !important;visibility:visible !important}.ibo-is-hidden{display:none !important}.ibo-is-transparent{opacity:0 !important}.ibo-is-opaque{opacity:1 !important}.content:not(:last-child),.ibo-is-html-content:not(:last-child){margin-bottom:1.5rem}/*! minireset.css v0.0.6 | MIT License | github.com/jgthms/minireset.css */html,body,p,ol,ul,li,dl,dt,dd,blockquote,figure,fieldset,legend,textarea,pre,iframe,hr,h1,h2,h3,h4,h5,h6{margin:0;padding:0}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal}ul{list-style:none}button,input,select,textarea{margin:0}html{box-sizing:border-box}*,*::before,*::after{box-sizing:inherit}img,video{height:auto;max-width:100%}iframe{border:0}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}td:not([align]),th:not([align]){text-align:inherit}html{background-color:white;font-size:16px;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;min-width:300px;overflow-x:hidden;overflow-y:auto;text-rendering:optimizeLegibility;text-size-adjust:100%}article,aside,figure,footer,header,hgroup,section{display:block}body,button,input,optgroup,select,textarea{font-family:"Raleway", "sans-serif", "system-ui"}code,pre{-moz-osx-font-smoothing:auto;-webkit-font-smoothing:auto;font-family:monospace}body{color:#212934;font-size:1rem;font-weight:500;line-height:1.5}a{color:#485fc7;cursor:pointer;text-decoration:none}a strong{color:currentColor}a:hover{color:#363636}code{background-color:whitesmoke;color:#da1039;font-size:0.875em;font-weight:normal;padding:0.25em 0.5em 0.25em}hr{background-color:whitesmoke;border:none;display:block;height:2px;margin:1.5rem 0}img{height:auto;max-width:100%}input[type="checkbox"],input[type="radio"]{vertical-align:baseline}small{font-size:0.875em}span{font-style:inherit;font-weight:inherit}strong{color:inherit;font-weight:700}fieldset{border:none}pre{-webkit-overflow-scrolling:touch;background-color:whitesmoke;color:#4a4a4a;font-size:0.875em;overflow-x:auto;padding:1.25rem 1.5rem;white-space:pre;word-wrap:normal}pre code{background-color:transparent;color:currentColor;font-size:1em;padding:0}table td,table th{vertical-align:top}table td:not([align]),table th:not([align]){text-align:inherit}table th{color:inherit}@keyframes spinAround{from{transform:rotate(0deg)}to{transform:rotate(359deg)}}.content li+li,.ibo-is-html-content li+li{margin-top:0.25em}.content p:not(:last-child),.ibo-is-html-content p:not(:last-child),.content dl:not(:last-child),.ibo-is-html-content dl:not(:last-child),.content ol:not(:last-child),.ibo-is-html-content ol:not(:last-child),.content ul:not(:last-child),.ibo-is-html-content ul:not(:last-child),.content blockquote:not(:last-child),.ibo-is-html-content blockquote:not(:last-child),.content pre:not(:last-child),.ibo-is-html-content pre:not(:last-child),.content table:not(:last-child),.ibo-is-html-content table:not(:last-child){margin-bottom:0}.content h1,.ibo-is-html-content h1,.content h2,.ibo-is-html-content h2,.content h3,.ibo-is-html-content h3,.content h4,.ibo-is-html-content h4,.content h5,.ibo-is-html-content h5,.content h6,.ibo-is-html-content h6{color:inherit;font-weight:600;line-height:1.125}.content h1,.ibo-is-html-content h1{font-size:2em;margin-bottom:0.5em}.content h1:not(:first-child),.ibo-is-html-content h1:not(:first-child){margin-top:1em}.content h2,.ibo-is-html-content h2{font-size:1.75em;margin-bottom:0.5714em}.content h2:not(:first-child),.ibo-is-html-content h2:not(:first-child){margin-top:1.1428em}.content h3,.ibo-is-html-content h3{font-size:1.5em;margin-bottom:0.6666em}.content h3:not(:first-child),.ibo-is-html-content h3:not(:first-child){margin-top:1.3333em}.content h4,.ibo-is-html-content h4{font-size:1.25em;margin-bottom:0.8em}.content h5,.ibo-is-html-content h5{font-size:1.125em;margin-bottom:0.8888em}.content h6,.ibo-is-html-content h6{font-size:1em;margin-bottom:1em}.content blockquote,.ibo-is-html-content blockquote{background-color:#e1e7ec;border-left:5px solid #dbdbdb;padding:1.25em 1.5em}.content ol,.ibo-is-html-content ol{list-style-position:outside;margin-left:2em;margin-top:1em}.content ol:not([type]),.ibo-is-html-content ol:not([type]){list-style-type:decimal}.content ol:not([type]).is-lower-alpha,.ibo-is-html-content ol:not([type]).is-lower-alpha{list-style-type:lower-alpha}.content ol:not([type]).is-lower-roman,.ibo-is-html-content ol:not([type]).is-lower-roman{list-style-type:lower-roman}.content ol:not([type]).is-upper-alpha,.ibo-is-html-content ol:not([type]).is-upper-alpha{list-style-type:upper-alpha}.content ol:not([type]).is-upper-roman,.ibo-is-html-content ol:not([type]).is-upper-roman{list-style-type:upper-roman}.content ul,.ibo-is-html-content ul{list-style:disc outside;margin-left:2em;margin-top:1em}.content ul ul,.ibo-is-html-content ul ul{list-style-type:circle;margin-top:0.5em}.content ul ul ul,.ibo-is-html-content ul ul ul{list-style-type:square}.content dd,.ibo-is-html-content dd{margin-left:2em}.content figure,.ibo-is-html-content figure{margin-left:2em;margin-right:2em;text-align:center}.content figure:not(:first-child),.ibo-is-html-content figure:not(:first-child){margin-top:2em}.content figure:not(:last-child),.ibo-is-html-content figure:not(:last-child){margin-bottom:2em}.content figure img,.ibo-is-html-content figure img{display:inline-block}.content figure figcaption,.ibo-is-html-content figure figcaption{font-style:italic}.content pre,.ibo-is-html-content pre{-webkit-overflow-scrolling:touch;overflow-x:auto;padding:1.25em 1.5em;white-space:pre;word-wrap:normal}.content sup,.ibo-is-html-content sup,.content sub,.ibo-is-html-content sub{font-size:75%}.content table,.ibo-is-html-content table{width:100%}.content table td,.ibo-is-html-content table td,.content table th,.ibo-is-html-content table th{border:"invalid on purpose";border-width:"invalid on purpose";padding:"invalid on purpose";vertical-align:top}.content table th,.ibo-is-html-content table th{color:"invalid on purpose"}.content table th:not([align]),.ibo-is-html-content table th:not([align]){text-align:inherit}.content table thead td,.ibo-is-html-content table thead td,.content table thead th,.ibo-is-html-content table thead th{border-width:"invalid on purpose";color:"invalid on purpose"}.content table tfoot td,.ibo-is-html-content table tfoot td,.content table tfoot th,.ibo-is-html-content table tfoot th{border-width:"invalid on purpose";color:"invalid on purpose"}.content table tbody tr:last-child td,.ibo-is-html-content table tbody tr:last-child td,.content table tbody tr:last-child th,.ibo-is-html-content table tbody tr:last-child th{border-bottom-width:1px}.content .tabs li+li,.ibo-is-html-content .tabs li+li{margin-top:0}.content.is-small,.is-small.ibo-is-html-content{font-size:0.75rem}.content.is-normal,.is-normal.ibo-is-html-content{font-size:1rem}.content.is-medium,.is-medium.ibo-is-html-content{font-size:1.25rem}.content.is-large,.is-large.ibo-is-html-content{font-size:1.5rem}.common-hljs-container{padding:0 !important;border:none !important}pre code.hljs{display:block;overflow-x:auto;padding:0.9rem !important}code.hljs{padding:4px 4px !important}.hljs{box-shadow:0 0px 3px 2px inset rgba(0, 0, 0, 0.4) !important;border-radius:3px !important;white-space:pre-wrap;border:none !important;color:#e0e2e4 !important;background:#282b2e !important}.hljs-keyword,.hljs-selector-tag,.hljs-literal,.hljs-selector-id{color:#93c763 !important}.hljs-number{color:#ffcd22 !important}.hljs-attribute{color:#668bb0}.hljs-regexp,.hljs-link{color:#d39745 !important}.hljs-meta{color:#557182 !important}.hljs-tag,.hljs-name,.hljs-bullet,.hljs-subst,.hljs-emphasis,.hljs-type,.hljs-built_in,.hljs-selector-attr,.hljs-selector-pseudo,.hljs-addition,.hljs-variable,.hljs-template-tag,.hljs-template-variable{color:#8cbbad !important}.hljs-string,.hljs-symbol{color:#ec7600 !important}.hljs-comment,.hljs-quote,.hljs-deletion{color:#818e96 !important}.hljs-selector-class{color:#A082BD !important}.hljs-keyword,.hljs-selector-tag,.hljs-literal,.hljs-doctag,.hljs-title,.hljs-section,.hljs-type,.hljs-name,.hljs-strong{font-weight:bold}.hljs-code,.hljs-title.class_,.hljs-class .hljs-title,.hljs-section{color:white !important}:root{--ck-color-base-foreground: #fafafa;--ck-color-base-background: #fff;--ck-color-base-border: #ccced1;--ck-color-base-action: #53a336;--ck-color-base-focus: #6cb5f9;--ck-color-base-text: #333;--ck-color-base-active: #2977ff;--ck-color-base-active-focus: #0d65ff;--ck-color-base-error: #db3700;--ck-color-focus-border-coordinates: 218, 81.8%, 56.9%;--ck-color-focus-border: hsl(var(--ck-color-focus-border-coordinates));--ck-color-focus-outer-shadow: #cae1fc;--ck-color-focus-disabled-shadow: #77baf84d;--ck-color-focus-error-shadow: #ff401f4d;--ck-color-text: var(--ck-color-base-text);--ck-color-shadow-drop: #00000026;--ck-color-shadow-drop-active: #0003;--ck-color-shadow-inner: #0000001a;--ck-color-button-default-background: transparent;--ck-color-button-default-hover-background: #f0f0f0;--ck-color-button-default-active-background: #f0f0f0;--ck-color-button-default-disabled-background: transparent;--ck-color-button-on-background: #f0f7ff;--ck-color-button-on-hover-background: #dbecff;--ck-color-button-on-active-background: #dbecff;--ck-color-button-on-disabled-background: #f0f2f4;--ck-color-button-on-color: #2977ff;--ck-color-button-action-background: var(--ck-color-base-action);--ck-color-button-action-hover-background: #4d9d30;--ck-color-button-action-active-background: #4d9d30;--ck-color-button-action-disabled-background: #7ec365;--ck-color-button-action-text: var(--ck-color-base-background);--ck-color-button-save: #008a00;--ck-color-button-cancel: #db3700;--ck-color-switch-button-off-background: #939393;--ck-color-switch-button-off-hover-background: #7d7d7d;--ck-color-switch-button-on-background: var(--ck-color-button-action-background);--ck-color-switch-button-on-hover-background: #4d9d30;--ck-color-switch-button-inner-background: var(--ck-color-base-background);--ck-color-switch-button-inner-shadow: #0000001a;--ck-color-dropdown-panel-background: var(--ck-color-base-background);--ck-color-dropdown-panel-border: var(--ck-color-base-border);--ck-color-dialog-background: var(--ck-custom-background);--ck-color-dialog-form-header-border: var(--ck-custom-border);--ck-color-input-background: var(--ck-color-base-background);--ck-color-input-border: var(--ck-color-base-border);--ck-color-input-error-border: var(--ck-color-base-error);--ck-color-input-text: var(--ck-color-base-text);--ck-color-input-disabled-background: #f2f2f2;--ck-color-input-disabled-border: var(--ck-color-base-border);--ck-color-input-disabled-text: #757575;--ck-color-list-background: var(--ck-color-base-background);--ck-color-list-button-hover-background: var(--ck-color-button-default-hover-background);--ck-color-list-button-on-background: var(--ck-color-button-on-color);--ck-color-list-button-on-background-focus: var(--ck-color-button-on-color);--ck-color-list-button-on-text: var(--ck-color-base-background);--ck-color-panel-background: var(--ck-color-base-background);--ck-color-panel-border: var(--ck-color-base-border);--ck-color-toolbar-background: var(--ck-color-base-background);--ck-color-toolbar-border: var(--ck-color-base-border);--ck-color-tooltip-background: var(--ck-color-base-text);--ck-color-tooltip-text: var(--ck-color-base-background);--ck-color-engine-placeholder-text: #707070;--ck-color-upload-bar-background: #6cb5f9;--ck-color-link-default: #0000f0;--ck-color-link-selected-background: #1fb0ff1a;--ck-color-link-fake-selection: #1fb0ff4d;--ck-color-highlight-background: #ff0;--ck-color-light-red: #fcc;--ck-disabled-opacity: .5;--ck-focus-outer-shadow-geometry: 0 0 0 3px;--ck-focus-outer-shadow: var(--ck-focus-outer-shadow-geometry) var(--ck-color-focus-outer-shadow);--ck-focus-disabled-outer-shadow: var(--ck-focus-outer-shadow-geometry) var(--ck-color-focus-disabled-shadow);--ck-focus-error-outer-shadow: var(--ck-focus-outer-shadow-geometry) var(--ck-color-focus-error-shadow);--ck-focus-ring: 1px solid var(--ck-color-focus-border);--ck-font-size-base: 13px;--ck-line-height-base: 1.84615;--ck-font-face: Helvetica, Arial, Tahoma, Verdana, Sans-Serif;--ck-font-size-tiny: .7em;--ck-font-size-small: .75em;--ck-font-size-normal: 1em;--ck-font-size-big: 1.4em;--ck-font-size-large: 1.8em;--ck-ui-component-min-height: 2.3em}.ck.ck-reset,.ck.ck-reset_all,.ck-reset_all :not(.ck-reset_all-excluded, .ck-reset_all-excluded *){box-sizing:border-box;vertical-align:middle;word-wrap:break-word;background:none;border:0;width:auto;height:auto;margin:0;padding:0;text-decoration:none;transition:none;position:static}.ck.ck-reset_all,.ck-reset_all :not(.ck-reset_all-excluded, .ck-reset_all-excluded *){border-collapse:collapse;font:normal normal normal var(--ck-font-size-base)/var(--ck-line-height-base) var(--ck-font-face);color:var(--ck-color-text);text-align:left;white-space:nowrap;cursor:auto;float:none}.ck-reset_all .ck-rtl :not(.ck-reset_all-excluded, .ck-reset_all-excluded *){text-align:right}.ck-reset_all iframe:not(.ck-reset_all-excluded *){vertical-align:inherit}.ck-reset_all textarea:not(.ck-reset_all-excluded *){white-space:pre-wrap}.ck-reset_all textarea:not(.ck-reset_all-excluded *),.ck-reset_all input[type="text"]:not(.ck-reset_all-excluded *),.ck-reset_all input[type="password"]:not(.ck-reset_all-excluded *){cursor:text}.ck-reset_all textarea[disabled]:not(.ck-reset_all-excluded *),.ck-reset_all input[type="text"][disabled]:not(.ck-reset_all-excluded *),.ck-reset_all input[type="password"][disabled]:not(.ck-reset_all-excluded *){cursor:default}.ck-reset_all fieldset:not(.ck-reset_all-excluded *){border:2px groove #dfdee3;padding:10px}.ck-reset_all button:not(.ck-reset_all-excluded *)::-moz-focus-inner{border:0;padding:0}.ck[dir="rtl"],.ck[dir="rtl"] .ck{text-align:right}:root{--ck-border-radius: 2px;--ck-rounded-corners-radius: 0}.ck-rounded-corners{--ck-rounded-corners-radius: var(--ck-border-radius)}:root{--ck-inner-shadow: 2px 2px 3px var(--ck-color-shadow-inner) inset;--ck-drop-shadow: 0 1px 2px 1px var(--ck-color-shadow-drop);--ck-drop-shadow-active: 0 3px 6px 1px var(--ck-color-shadow-drop-active);--ck-spacing-unit: .6em;--ck-spacing-extra-large: calc(var(--ck-spacing-unit) * 2);--ck-spacing-large: calc(var(--ck-spacing-unit) * 1.5);--ck-spacing-standard: var(--ck-spacing-unit);--ck-spacing-medium: calc(var(--ck-spacing-unit) * .8);--ck-spacing-medium-small: calc(var(--ck-spacing-unit) * .667);--ck-spacing-small: calc(var(--ck-spacing-unit) * .5);--ck-spacing-tiny: calc(var(--ck-spacing-unit) * .3);--ck-spacing-extra-tiny: calc(var(--ck-spacing-unit) * .16)}.ck-hidden{display:none !important}:root{--ck-z-default: 1;--ck-z-panel: calc(var(--ck-z-default) + 999);--ck-z-dialog: 9999}.ck-transitions-disabled,.ck-transitions-disabled *{transition:none !important}:root{--ck-powered-by-font-size: calc(var(--ck-font-size-base) * 7.5 / 13);--ck-powered-by-line-height: calc(var(--ck-font-size-base) * 10 / 13);--ck-powered-by-letter-spacing: calc(var(--ck-font-size-base) * -.2 / 13);--ck-powered-by-padding-vertical: 2px;--ck-powered-by-padding-horizontal: 4px;--ck-powered-by-text-color: #4f4f4f;--ck-powered-by-border-radius: var(--ck-border-radius);--ck-powered-by-background: #fff;--ck-powered-by-border-color: var(--ck-color-focus-border);--ck-powered-by-svg-width: 53;--ck-powered-by-svg-height: 10;--ck-powered-by-icon-width: calc(var(--ck-font-size-base) * var(--ck-powered-by-svg-width) / 13);--ck-powered-by-icon-height: calc(var(--ck-font-size-base) * var(--ck-powered-by-svg-height) / 13)}.ck.ck-balloon-panel.ck-powered-by-balloon{--ck-border-radius: var(--ck-powered-by-border-radius);box-shadow:none;background:var(--ck-powered-by-background);min-height:unset;z-index:calc(var(--ck-z-panel) - 1)}.ck.ck-balloon-panel.ck-powered-by-balloon .ck.ck-powered-by{line-height:var(--ck-powered-by-line-height)}.ck.ck-balloon-panel.ck-powered-by-balloon .ck.ck-powered-by a{cursor:pointer;opacity:0.66;filter:grayscale(80%);line-height:var(--ck-powered-by-line-height);padding:var(--ck-powered-by-padding-vertical) var(--ck-powered-by-padding-horizontal);align-items:center;display:flex}.ck.ck-balloon-panel.ck-powered-by-balloon .ck.ck-powered-by .ck-powered-by__label{font-size:var(--ck-powered-by-font-size);letter-spacing:var(--ck-powered-by-letter-spacing);text-transform:uppercase;cursor:pointer;color:var(--ck-powered-by-text-color);margin-right:4px;padding-left:2px;font-weight:bold;line-height:normal}.ck.ck-balloon-panel.ck-powered-by-balloon .ck.ck-powered-by .ck-icon{cursor:pointer;width:var(--ck-powered-by-icon-width);height:var(--ck-powered-by-icon-height);display:block}.ck.ck-balloon-panel.ck-powered-by-balloon .ck.ck-powered-by:hover a{filter:grayscale(0%);opacity:1}.ck.ck-balloon-panel.ck-powered-by-balloon[class*="position_inside"]{border-color:#0000}.ck.ck-balloon-panel.ck-powered-by-balloon[class*="position_border"]{border:var(--ck-focus-ring);border-color:var(--ck-powered-by-border-color)}:root{--ck-evaluation-badge-font-size: calc(var(--ck-font-size-base) * 7.5 / 13);--ck-evaluation-badge-line-height: calc(var(--ck-font-size-base) * 7.5 / 13);--ck-evaluation-badge-letter-spacing: calc(var(--ck-font-size-base) * -.2 / 13);--ck-evaluation-badge-padding-vertical: 2px;--ck-evaluation-badge-padding-horizontal: 4px;--ck-evaluation-badge-text-color: #4f4f4f;--ck-evaluation-badge-border-radius: var(--ck-border-radius);--ck-evaluation-badge-background: #fff;--ck-evaluation-badge-border-color: var(--ck-color-focus-border)}.ck.ck-balloon-panel.ck-evaluation-badge-balloon{--ck-border-radius: var(--ck-evaluation-badge-border-radius);box-shadow:none;background:var(--ck-evaluation-badge-background);min-height:unset;z-index:calc(var(--ck-z-panel) - 1)}.ck.ck-balloon-panel.ck-evaluation-badge-balloon .ck.ck-evaluation-badge{line-height:var(--ck-evaluation-badge-line-height);padding:var(--ck-evaluation-badge-padding-vertical) var(--ck-evaluation-badge-padding-horizontal)}.ck.ck-balloon-panel.ck-evaluation-badge-balloon .ck.ck-evaluation-badge .ck-evaluation-badge__label{font-size:var(--ck-evaluation-badge-font-size);letter-spacing:var(--ck-evaluation-badge-letter-spacing);text-transform:uppercase;color:var(--ck-evaluation-badge-text-color);padding:0 2px;font-weight:bold;line-height:normal;display:block}.ck.ck-balloon-panel.ck-evaluation-badge-balloon[class*="position_inside"]{border-color:#0000}.ck.ck-balloon-panel.ck-evaluation-badge-balloon[class*="position_border"]{border:var(--ck-focus-ring);border-color:var(--ck-evaluation-badge-border-color)}.ck.ck-responsive-form{padding:var(--ck-spacing-large)}.ck.ck-responsive-form:focus{outline:none}[dir="ltr"] .ck.ck-responsive-form>:not(:first-child){margin-left:var(--ck-spacing-standard)}[dir="rtl"] .ck.ck-responsive-form>:not(:last-child){margin-left:var(--ck-spacing-standard)}@media screen and (width <= 600px){.ck.ck-responsive-form{width:calc(.8 * var(--ck-input-width));padding:0}.ck.ck-responsive-form .ck-labeled-field-view{margin:var(--ck-spacing-large) var(--ck-spacing-large) 0}.ck.ck-responsive-form .ck-labeled-field-view .ck-input-text,.ck.ck-responsive-form .ck-labeled-field-view .ck-input-number{width:100%;min-width:0}.ck.ck-responsive-form .ck-labeled-field-view .ck-labeled-field-view__error{white-space:normal}.ck.ck-responsive-form>.ck-button:last-child,.ck.ck-responsive-form>.ck-button:nth-last-child(2){padding:var(--ck-spacing-standard);margin-top:var(--ck-spacing-large);border-radius:0}:is(.ck.ck-responsive-form>.ck-button:last-child, .ck.ck-responsive-form>.ck-button:nth-last-child(2)):not(:focus){border-top:1px solid var(--ck-color-base-border)}[dir="ltr"] :is(.ck.ck-responsive-form>.ck-button:last-child, .ck.ck-responsive-form>.ck-button:nth-last-child(2)){margin-left:0}[dir="rtl"] :is(.ck.ck-responsive-form>.ck-button:last-child, .ck.ck-responsive-form>.ck-button:nth-last-child(2)){margin-left:0}[dir="rtl"] :is(.ck.ck-responsive-form>.ck-button:last-child, .ck.ck-responsive-form>.ck-button:nth-last-child(2)):last-of-type{border-right:1px solid var(--ck-color-base-border)}.ck.ck-responsive-form .ck-button:after{content:"";z-index:1;width:0;position:absolute;top:-1px;bottom:-1px;right:-1px}.ck.ck-responsive-form .ck-button:nth-last-child(2):after{border-right:1px solid var(--ck-color-base-border)}.ck.ck-responsive-form .ck-button:focus:after{display:none}}.ck-vertical-form>.ck-button:nth-last-child(2):after{border-right:1px solid var(--ck-color-base-border)}.ck-vertical-form .ck-button:after{content:"";z-index:1;width:0;position:absolute;top:-1px;bottom:-1px;right:-1px}.ck-vertical-form .ck-button:focus:after{display:none}:root{--ck-form-default-width: 340px}.ck.ck-form{padding:0 0 var(--ck-spacing-large)}.ck.ck-form.ck-form_default-width{width:var(--ck-form-default-width)}.ck.ck-form:focus{outline:none}.ck.ck-form .ck.ck-input-text,.ck.ck-form .ck.ck-input-number{width:0;min-width:100%}.ck.ck-form .ck.ck-dropdown{min-width:100%}.ck.ck-form .ck.ck-dropdown .ck-dropdown__button:not(:focus){border:1px solid var(--ck-color-base-border)}.ck.ck-form .ck.ck-dropdown .ck-dropdown__button .ck-button__label{width:100%}@media screen and (width <= 600px){.ck.ck-form.ck-responsive-form .ck.ck-form__row.ck-form__row_with-submit{flex-direction:column;align-items:stretch;padding:0}}@media screen and (width <= 600px){.ck.ck-form.ck-responsive-form .ck.ck-form__row.ck-form__row_with-submit>.ck{margin:var(--ck-spacing-large) var(--ck-spacing-large) 0}}@media screen and (width <= 600px){.ck.ck-form.ck-responsive-form .ck.ck-form__row.ck-form__row_with-submit .ck-button_with-text{justify-content:center}}@media screen and (width <= 600px){.ck.ck-form.ck-responsive-form .ck.ck-form__row.ck-form__row_large-bottom-padding{padding-bottom:var(--ck-spacing-large)}}[dir="ltr"] .ck.ck-form.ck-responsive-form>:not(:first-child){margin-left:0}[dir="rtl"] .ck.ck-form.ck-responsive-form>:not(:last-child){margin-left:0}.ck.ck-aria-live-announcer{position:absolute;top:-10000px;left:-10000px}.ck.ck-aria-live-region-list{list-style-type:none}:root{--ck-accessibility-help-dialog-max-width: 600px;--ck-accessibility-help-dialog-max-height: 400px;--ck-accessibility-help-dialog-border-color: #ccced1;--ck-accessibility-help-dialog-code-background-color: #ededed;--ck-accessibility-help-dialog-kbd-shadow-color: #9c9c9c}.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content{padding:var(--ck-spacing-large);max-width:var(--ck-accessibility-help-dialog-max-width);max-height:var(--ck-accessibility-help-dialog-max-height);user-select:text;border:1px solid #0000;overflow:auto}.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content:focus{border:var(--ck-focus-ring);box-shadow:var(--ck-focus-outer-shadow), 0 0;outline:none}.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content *{white-space:normal}.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content .ck-label{display:none}.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content h3{font-size:1.2em;font-weight:bold}.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content h4{font-size:1em;font-weight:bold}.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content p,.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content h3,.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content h4,.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content table{margin:1em 0}.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content dl{border-top:1px solid var(--ck-accessibility-help-dialog-border-color);border-bottom:none;grid-template-columns:2fr 1fr;display:grid}.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content dl dt,.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content dl dd{border-bottom:1px solid var(--ck-accessibility-help-dialog-border-color);padding:0.4em 0}.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content dl dt{grid-column-start:1}.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content dl dd{text-align:right;grid-column-start:2}.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content kbd,.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content code{background:var(--ck-accessibility-help-dialog-code-background-color);vertical-align:middle;text-align:center;border-radius:2px;padding:0.4em;font-size:0.9em;line-height:1;display:inline-block}.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content code{font-family:monospace}.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content kbd{min-width:1.8em;box-shadow:0px 1px 1px var(--ck-accessibility-help-dialog-kbd-shadow-color);margin:0 1px}.ck.ck-accessibility-help-dialog .ck-accessibility-help-dialog__content kbd+kbd{margin-left:2px}.ck.ck-button,:where(a).ck.ck-button{--ck-button-background: var(--ck-color-button-default-background);--ck-button-hover-background: var(--ck-color-button-default-hover-background);--ck-button-active-background: var(--ck-color-button-default-active-background);--ck-button-disabled-background: var(--ck-color-button-default-disabled-background);background:var(--ck-button-background)}:is(.ck.ck-button, :where(a).ck.ck-button):not(.ck-disabled):hover{background:var(--ck-button-hover-background)}:is(.ck.ck-button, :where(a).ck.ck-button):not(.ck-disabled):active{background:var(--ck-button-active-background)}.ck.ck-button,:where(a).ck.ck-button{border-radius:var(--ck-rounded-corners-radius);white-space:nowrap;cursor:default;vertical-align:middle;padding:var(--ck-spacing-tiny);text-align:center;min-width:var(--ck-ui-component-min-height);min-height:var(--ck-ui-component-min-height);line-height:1;font-size:inherit;-webkit-appearance:none;-webkit-user-select:none;user-select:none;border:1px solid #0000;align-items:center;transition:box-shadow 0.2s ease-in-out, border 0.2s ease-in-out;display:inline-flex;position:relative}@media (prefers-reduced-motion:reduce){.ck.ck-button,:where(a).ck.ck-button{transition:none}}:is(.ck.ck-button, :where(a).ck.ck-button):active,:is(.ck.ck-button, :where(a).ck.ck-button):focus{border:var(--ck-focus-ring);box-shadow:var(--ck-focus-outer-shadow), 0 0;outline:none}:is(.ck.ck-button, :where(a).ck.ck-button) .ck-button__icon use,:is(.ck.ck-button, :where(a).ck.ck-button) .ck-button__icon use *{color:inherit}:is(.ck.ck-button, :where(a).ck.ck-button) .ck-button__label{font-size:inherit;font-weight:inherit;color:inherit;cursor:inherit;vertical-align:middle}[dir="ltr"] :is(:is(.ck.ck-button, :where(a).ck.ck-button) .ck-button__label){text-align:left}[dir="rtl"] :is(:is(.ck.ck-button, :where(a).ck.ck-button) .ck-button__label){text-align:right}:is(.ck.ck-button, :where(a).ck.ck-button) .ck-button__label{display:none}:is(.ck.ck-button, :where(a).ck.ck-button) .ck-button__keystroke{color:inherit;opacity:0.5}[dir="ltr"] :is(:is(.ck.ck-button, :where(a).ck.ck-button) .ck-button__keystroke){margin-left:var(--ck-spacing-large)}[dir="rtl"] :is(:is(.ck.ck-button, :where(a).ck.ck-button) .ck-button__keystroke){margin-right:var(--ck-spacing-large)}:is(.ck.ck-button, :where(a).ck.ck-button).ck-disabled{background:var(--ck-button-disabled-background)}:is(.ck.ck-button, :where(a).ck.ck-button).ck-disabled:active,:is(.ck.ck-button, :where(a).ck.ck-button).ck-disabled:focus{box-shadow:var(--ck-focus-disabled-outer-shadow), 0 0}:is(.ck.ck-button, :where(a).ck.ck-button).ck-disabled .ck-button__icon,:is(.ck.ck-button, :where(a).ck.ck-button).ck-disabled .ck-button__label{opacity:var(--ck-disabled-opacity)}:is(.ck.ck-button, :where(a).ck.ck-button).ck-disabled .ck-button__keystroke{opacity:0.3}:is(.ck.ck-button, :where(a).ck.ck-button).ck-button_with-text{padding:var(--ck-spacing-tiny) var(--ck-spacing-standard)}[dir="ltr"] :is(:is(.ck.ck-button, :where(a).ck.ck-button).ck-button_with-text .ck-button__icon){margin-right:var(--ck-spacing-medium)}[dir="rtl"] :is(:is(.ck.ck-button, :where(a).ck.ck-button).ck-button_with-text .ck-button__icon){margin-left:var(--ck-spacing-medium)}:is(.ck.ck-button, :where(a).ck.ck-button).ck-button_with-text .ck-button__label{display:inline-block}:is(.ck.ck-button, :where(a).ck.ck-button).ck-button_with-keystroke .ck-button__label{flex-grow:1}:is(.ck.ck-button, :where(a).ck.ck-button).ck-on{--ck-button-background: var(--ck-color-button-on-background);--ck-button-hover-background: var(--ck-color-button-on-hover-background);--ck-button-active-background: var(--ck-color-button-on-active-background);--ck-button-disabled-background: var(--ck-color-button-on-disabled-background);color:var(--ck-color-button-on-color)}:is(.ck.ck-button, :where(a).ck.ck-button).ck-button-save{color:var(--ck-color-button-save)}:is(.ck.ck-button, :where(a).ck.ck-button).ck-button-cancel{color:var(--ck-color-button-cancel)}[dir="ltr"] :is(.ck.ck-button, :where(a).ck.ck-button){justify-content:left}[dir="rtl"] :is(.ck.ck-button, :where(a).ck.ck-button){justify-content:right}:is(.ck.ck-button, :where(a).ck.ck-button):not(.ck-button_with-text){justify-content:center}.ck.ck-button-action,a.ck.ck-button-action{--ck-button-background: var(--ck-color-button-action-background);--ck-button-hover-background: var(--ck-color-button-action-hover-background);--ck-button-active-background: var(--ck-color-button-action-active-background);--ck-button-disabled-background: var(--ck-color-button-action-disabled-background);color:var(--ck-color-button-action-text)}.ck.ck-button-bold,a.ck.ck-button-bold{font-weight:bold}:root{--ck-switch-button-toggle-width: 2.61538em;--ck-switch-button-toggle-inner-size: calc(1.07692em + 1px);--ck-switch-button-translation: calc(var(--ck-switch-button-toggle-width) - var(--ck-switch-button-toggle-inner-size) - 2px /* Border */);--ck-switch-button-inner-hover-shadow: 0 0 0 5px var(--ck-color-switch-button-inner-shadow)}.ck.ck-button.ck-switchbutton,.ck.ck-button.ck-switchbutton:hover,.ck.ck-button.ck-switchbutton:focus,.ck.ck-button.ck-switchbutton:active,.ck.ck-button.ck-switchbutton.ck-on:hover,.ck.ck-button.ck-switchbutton.ck-on:focus,.ck.ck-button.ck-switchbutton.ck-on:active{color:inherit;background:none}[dir="ltr"] :is(.ck.ck-button.ck-switchbutton .ck-button__label){margin-right:calc(2 * var(--ck-spacing-large))}[dir="rtl"] :is(.ck.ck-button.ck-switchbutton .ck-button__label){margin-left:calc(2 * var(--ck-spacing-large))}.ck.ck-button.ck-switchbutton .ck-button__toggle{border-radius:var(--ck-rounded-corners-radius);width:var(--ck-switch-button-toggle-width);background:var(--ck-color-switch-button-off-background);border:1px solid #0000;transition:background 0.4s, box-shadow 0.2s ease-in-out, outline 0.2s ease-in-out}[dir="ltr"] :is(.ck.ck-button.ck-switchbutton .ck-button__toggle){margin-left:auto}[dir="rtl"] :is(.ck.ck-button.ck-switchbutton .ck-button__toggle){margin-right:auto}.ck.ck-button.ck-switchbutton .ck-button__toggle .ck-button__toggle__inner{border-radius:calc(.5 * var(--ck-rounded-corners-radius));width:var(--ck-switch-button-toggle-inner-size);height:var(--ck-switch-button-toggle-inner-size);background:var(--ck-color-switch-button-inner-background);transition:all 0.3s}@media (prefers-reduced-motion:reduce){.ck.ck-button.ck-switchbutton .ck-button__toggle .ck-button__toggle__inner{transition:none}}.ck.ck-button.ck-switchbutton .ck-button__toggle .ck-button__toggle__inner{display:block}.ck.ck-button.ck-switchbutton .ck-button__toggle:hover{background:var(--ck-color-switch-button-off-hover-background)}.ck.ck-button.ck-switchbutton .ck-button__toggle:hover .ck-button__toggle__inner{box-shadow:var(--ck-switch-button-inner-hover-shadow)}.ck.ck-button.ck-switchbutton .ck-button__toggle{display:block}.ck.ck-button.ck-switchbutton.ck-disabled .ck-button__toggle{opacity:var(--ck-disabled-opacity)}.ck.ck-button.ck-switchbutton:focus{box-shadow:none;border-color:#0000;outline:none}.ck.ck-button.ck-switchbutton:focus .ck-button__toggle{box-shadow:0 0 0 1px var(--ck-color-base-background), 0 0 0 5px var(--ck-color-focus-outer-shadow);outline-offset:1px;outline:var(--ck-focus-ring)}.ck.ck-button.ck-switchbutton.ck-on .ck-button__toggle{background:var(--ck-color-switch-button-on-background)}.ck.ck-button.ck-switchbutton.ck-on .ck-button__toggle:hover{background:var(--ck-color-switch-button-on-hover-background)}[dir="ltr"] :is(.ck.ck-button.ck-switchbutton.ck-on .ck-button__toggle .ck-button__toggle__inner){transform:translateX(var(--ck-switch-button-translation))}[dir="rtl"] :is(.ck.ck-button.ck-switchbutton.ck-on .ck-button__toggle .ck-button__toggle__inner){transform:translateX(calc(-1 * var(--ck-switch-button-translation)))}.ck.ck-button.ck-list-item-button{padding:var(--ck-spacing-tiny) calc(2 * var(--ck-spacing-standard))}.ck.ck-button.ck-list-item-button,.ck.ck-button.ck-list-item-button.ck-on{background:var(--ck-color-list-background);color:var(--ck-color-text)}[dir="ltr"] .ck.ck-button.ck-list-item-button:has(.ck-list-item-button__check-holder){padding-left:var(--ck-spacing-small)}[dir="rtl"] .ck.ck-button.ck-list-item-button:has(.ck-list-item-button__check-holder){padding-right:var(--ck-spacing-small)}.ck.ck-button.ck-list-item-button:hover:not(.ck-disabled),.ck.ck-button.ck-list-item-button.ck-button.ck-on:hover,.ck.ck-button.ck-list-item-button.ck-on:not(.ck-list-item-button_toggleable),.ck.ck-button.ck-list-item-button.ck-on:hover{background:var(--ck-color-list-button-hover-background)}:is(.ck.ck-button.ck-list-item-button:hover:not(.ck-disabled), .ck.ck-button.ck-list-item-button.ck-button.ck-on:hover, .ck.ck-button.ck-list-item-button.ck-on:not(.ck-list-item-button_toggleable), .ck.ck-button.ck-list-item-button.ck-on:hover):not(.ck-disabled){color:var(--ck-color-text)}.ck.ck-list-item-button{min-height:unset;border-radius:0;width:100%}[dir="ltr"] .ck.ck-list-item-button{text-align:left}[dir="rtl"] .ck.ck-list-item-button{text-align:right}[dir="ltr"] .ck.ck-list-item-button.ck-list-item-button_toggleable{padding-left:var(--ck-spacing-small)}[dir="rtl"] .ck.ck-list-item-button.ck-list-item-button_toggleable{padding-right:var(--ck-spacing-small)}.ck.ck-list-item-button .ck-list-item-button__check-holder{width:0.9em;height:0.9em;display:inline-flex}[dir="ltr"] :is(.ck.ck-list-item-button .ck-list-item-button__check-holder){margin-right:var(--ck-spacing-small)}[dir="rtl"] :is(.ck.ck-list-item-button .ck-list-item-button__check-holder){margin-left:var(--ck-spacing-small)}.ck.ck-list-item-button .ck-list-item-button__check-icon{height:100%}:root{--ck-collapsible-arrow-size: calc(.5 * var(--ck-icon-size))}.ck.ck-collapsible>.ck.ck-button{width:100%;color:inherit;border-radius:0;font-weight:bold}.ck.ck-collapsible>.ck.ck-button:focus{background:none}.ck.ck-collapsible>.ck.ck-button:active,.ck.ck-collapsible>.ck.ck-button:not(:focus),.ck.ck-collapsible>.ck.ck-button:hover:not(:focus){box-shadow:none;background:none;border-color:#0000}.ck.ck-collapsible>.ck.ck-button>.ck-icon{margin-right:var(--ck-spacing-medium);width:var(--ck-collapsible-arrow-size)}.ck.ck-collapsible>.ck-collapsible__children{padding:var(--ck-spacing-medium) var(--ck-spacing-large) var(--ck-spacing-large)}.ck.ck-collapsible.ck-collapsible_collapsed>.ck.ck-button .ck-icon{transform:rotate(-90deg)}.ck.ck-collapsible.ck-collapsible_collapsed>.ck-collapsible__children{display:none}:root{--ck-color-grid-tile-size: 24px;--ck-color-color-grid-check-icon: #166fd4}.ck.ck-color-grid{grid-gap:5px;padding:8px;display:grid}.ck.ck-color-grid__tile{transition:box-shadow 0.2s}@media (forced-colors:none){.ck.ck-color-grid__tile{width:var(--ck-color-grid-tile-size);height:var(--ck-color-grid-tile-size);min-width:var(--ck-color-grid-tile-size);min-height:var(--ck-color-grid-tile-size);border:0;padding:0}.ck.ck-color-grid__tile.ck-on,.ck.ck-color-grid__tile:focus:not(.ck-disabled),.ck.ck-color-grid__tile:hover:not(.ck-disabled){border:0}.ck.ck-color-grid__tile.ck-color-selector__color-tile_bordered{box-shadow:0 0 0 1px var(--ck-color-base-border)}.ck.ck-color-grid__tile.ck-on{box-shadow:inset 0 0 0 1px var(--ck-color-base-background), 0 0 0 2px var(--ck-color-base-text)}.ck.ck-color-grid__tile:focus:not(.ck-disabled),.ck.ck-color-grid__tile:hover:not(.ck-disabled){box-shadow:inset 0 0 0 1px var(--ck-color-base-background), 0 0 0 2px var(--ck-color-focus-border)}}@media (forced-colors:active){.ck.ck-color-grid__tile{width:unset;height:unset;min-width:unset;min-height:unset;padding:0 var(--ck-spacing-small)}.ck.ck-color-grid__tile .ck-button__label{display:inline-block}}@media (prefers-reduced-motion:reduce){.ck.ck-color-grid__tile{transition:none}}.ck.ck-color-grid__tile.ck-disabled{cursor:unset;transition:unset}.ck.ck-color-grid__tile .ck.ck-icon{color:var(--ck-color-color-grid-check-icon);display:none}.ck.ck-color-grid__tile.ck-on .ck.ck-icon{display:block}.ck.ck-color-grid__label{padding:0 var(--ck-spacing-standard)}.color-picker-hex-input{width:max-content}.color-picker-hex-input .ck.ck-input{min-width:unset}.ck.ck-color-picker__row{margin:var(--ck-spacing-large) 0 0;width:unset;flex-flow:row;justify-content:space-between;display:flex}.ck.ck-color-picker__row .ck.ck-labeled-field-view{padding-top:unset}.ck.ck-color-picker__row .ck.ck-input-text{width:unset}.ck.ck-color-picker__row .ck-color-picker__hash-view{padding-top:var(--ck-spacing-tiny);padding-right:var(--ck-spacing-medium)}.ck.ck-color-selector .ck-color-grids-fragment .ck-button.ck-color-selector__remove-color,.ck.ck-color-selector .ck-color-grids-fragment .ck-button.ck-color-selector__color-picker{align-items:center;width:100%;display:flex}[dir="rtl"] :is(.ck.ck-color-selector .ck-color-grids-fragment .ck-button.ck-color-selector__remove-color, .ck.ck-color-selector .ck-color-grids-fragment .ck-button.ck-color-selector__color-picker){justify-content:flex-start}.ck.ck-color-selector .ck-color-grids-fragment .ck-button.ck-color-selector__color-picker{padding:calc(var(--ck-spacing-standard) / 2) var(--ck-spacing-standard);border-bottom-right-radius:0;border-bottom-left-radius:0}.ck.ck-color-selector .ck-color-grids-fragment .ck-button.ck-color-selector__color-picker:not(:focus){border-top:1px solid var(--ck-color-base-border)}[dir="ltr"] :is(.ck.ck-color-selector .ck-color-grids-fragment .ck-button.ck-color-selector__color-picker .ck.ck-icon){margin-right:var(--ck-spacing-standard)}[dir="rtl"] :is(.ck.ck-color-selector .ck-color-grids-fragment .ck-button.ck-color-selector__color-picker .ck.ck-icon){margin-left:var(--ck-spacing-standard)}.ck.ck-color-selector .ck-color-grids-fragment label.ck.ck-color-grid__label{font-weight:unset}.ck.ck-color-selector .ck-color-picker-fragment .ck.ck-color-picker{padding:8px}.ck.ck-color-selector .ck-color-picker-fragment .ck.ck-color-picker .hex-color-picker{min-width:180px;height:100px}.ck.ck-color-selector .ck-color-picker-fragment .ck.ck-color-picker .hex-color-picker::part(saturation){border-radius:var(--ck-border-radius) var(--ck-border-radius) 0 0}.ck.ck-color-selector .ck-color-picker-fragment .ck.ck-color-picker .hex-color-picker::part(hue){border-radius:0 0 var(--ck-border-radius) var(--ck-border-radius)}.ck.ck-color-selector .ck-color-picker-fragment .ck.ck-color-picker .hex-color-picker::part(saturation-pointer),.ck.ck-color-selector .ck-color-picker-fragment .ck.ck-color-picker .hex-color-picker::part(hue-pointer){width:15px;height:15px}.ck.ck-color-selector .ck-color-picker-fragment .ck.ck-color-selector_action-bar{flex-direction:row;justify-content:space-around;padding:0 8px 8px;display:flex}.ck.ck-color-selector .ck-color-picker-fragment .ck.ck-color-selector_action-bar .ck-button-save,.ck.ck-color-selector .ck-color-picker-fragment .ck.ck-color-selector_action-bar .ck-button-cancel{flex:1}:root{--ck-dialog-overlay-background-color: #00000080;--ck-dialog-drop-shadow: 0px 0px 6px 2px #00000026;--ck-dialog-max-width: 100vw;--ck-dialog-max-height: 90vh;--ck-color-dialog-background: var(--ck-color-base-background);--ck-color-dialog-form-header-border: var(--ck-color-base-border)}.ck.ck-dialog-overlay{background:var(--ck-dialog-overlay-background-color);z-index:var(--ck-z-dialog);user-select:none;overscroll-behavior:none;animation:0.3s ck-dialog-fade-in;position:fixed;inset:0}.ck.ck-dialog-overlay.ck-dialog-overlay__transparent{pointer-events:none;background:none;animation:none}.ck.ck-dialog{border-radius:var(--ck-rounded-corners-radius);box-shadow:var(--ck-drop-shadow), 0 0;--ck-drop-shadow: var(--ck-dialog-drop-shadow);background:var(--ck-color-dialog-background);max-height:var(--ck-dialog-max-height);max-width:var(--ck-dialog-max-width);border:1px solid var(--ck-color-base-border);overscroll-behavior:contain;overscroll-behavior:none;width:fit-content;position:absolute}.ck.ck-dialog .ck.ck-form__header{border-bottom:1px solid var(--ck-color-dialog-form-header-border);flex-shrink:0}.ck.ck-dialog:not(.ck-dialog_modal) .ck.ck-form__header .ck-form__header__label{cursor:grab}.ck.ck-dialog-overlay.ck-dialog-overlay__transparent .ck.ck-dialog{pointer-events:all}.ck-dialog-scroll-locked{overflow:hidden}@keyframes ck-dialog-fade-in{0%{background:none}100%{background:var(--ck-dialog-overlay-background-color)}}.ck.ck-dialog .ck.ck-dialog__actions{padding:var(--ck-spacing-large);display:flex}.ck.ck-dialog .ck.ck-dialog__actions>*+*{margin-left:var(--ck-spacing-large)}.ck.ck-dialog .ck.ck-dialog__actions{justify-content:flex-end}:root{--ck-dropdown-arrow-size: calc(.5 * var(--ck-icon-size));--ck-dropdown-max-width: 75vw}.ck.ck-dropdown{font-size:inherit;display:inline-block;position:relative}.ck.ck-dropdown .ck-dropdown__arrow{width:var(--ck-dropdown-arrow-size);pointer-events:none;z-index:var(--ck-z-default)}[dir="ltr"] .ck.ck-dropdown .ck-dropdown__arrow{right:var(--ck-spacing-standard);margin-left:var(--ck-spacing-standard)}[dir="rtl"] .ck.ck-dropdown .ck-dropdown__arrow{left:var(--ck-spacing-standard);margin-right:var(--ck-spacing-small)}.ck.ck-dropdown.ck-disabled .ck-dropdown__arrow{opacity:var(--ck-disabled-opacity)}[dir="ltr"] :is(.ck.ck-dropdown .ck-button.ck-dropdown__button):not(.ck-button_with-text){padding-left:var(--ck-spacing-small)}[dir="rtl"] :is(.ck.ck-dropdown .ck-button.ck-dropdown__button):not(.ck-button_with-text){padding-right:var(--ck-spacing-small)}.ck.ck-dropdown .ck-button.ck-dropdown__button .ck-button__label{text-overflow:ellipsis;width:7em;overflow:hidden}.ck.ck-dropdown .ck-button.ck-dropdown__button.ck-disabled .ck-button__label{opacity:var(--ck-disabled-opacity)}.ck.ck-dropdown .ck-button.ck-dropdown__button.ck-on{border-bottom-right-radius:0;border-bottom-left-radius:0}.ck.ck-dropdown .ck-button.ck-dropdown__button.ck-dropdown__button_label-width_auto .ck-button__label{width:auto}.ck.ck-dropdown .ck-button.ck-dropdown__button.ck-off:active,.ck.ck-dropdown .ck-button.ck-dropdown__button.ck-on:active{box-shadow:none}:is(.ck.ck-dropdown .ck-button.ck-dropdown__button.ck-off:active, .ck.ck-dropdown .ck-button.ck-dropdown__button.ck-on:active):focus{box-shadow:var(--ck-focus-outer-shadow), 0 0}.ck.ck-dropdown .ck-button.ck-dropdown__button{width:100%}.ck.ck-dropdown .ck-dropdown__panel{z-index:var(--ck-z-panel);max-width:var(--ck-dropdown-max-width);display:none;position:absolute}.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel-visible{display:inline-block}.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_ne,.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_nw,.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_n,.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_nmw,.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_nme{bottom:100%}.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_se,.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_sw,.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_smw,.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_sme,.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_s{top:100%;bottom:auto}.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_ne,.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_se{left:0}.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_nw,.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_sw{right:0}.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_s,.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_n{left:50%;transform:translateX(-50%)}.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_nmw,.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_smw{left:75%;transform:translateX(-75%)}.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_nme,.ck.ck-dropdown .ck-dropdown__panel.ck-dropdown__panel_sme{left:25%;transform:translateX(-25%)}.ck.ck-dropdown__panel{border-radius:var(--ck-rounded-corners-radius);box-shadow:var(--ck-drop-shadow), 0 0;background:var(--ck-color-dropdown-panel-background);border:1px solid var(--ck-color-dropdown-panel-border);min-width:100%;bottom:0}.ck.ck-dropdown__panel.ck-dropdown__panel_se{border-top-left-radius:0}.ck.ck-dropdown__panel.ck-dropdown__panel_sw{border-top-right-radius:0}.ck.ck-dropdown__panel.ck-dropdown__panel_ne{border-bottom-left-radius:0}.ck.ck-dropdown__panel.ck-dropdown__panel_nw{border-bottom-right-radius:0}.ck.ck-dropdown__panel:focus{outline:none}.ck.ck-toolbar .ck-dropdown__panel{z-index:calc(var(--ck-z-panel) + 1)}:root{--ck-color-split-button-hover-background: #ebebeb;--ck-color-split-button-hover-border: #b3b3b3}.ck.ck-splitbutton .ck-splitbutton__action:focus{z-index:calc(var(--ck-z-default) + 1)}[dir="ltr"] :is(.ck.ck-splitbutton:hover>.ck-splitbutton__action, .ck.ck-splitbutton.ck-splitbutton_open>.ck-splitbutton__action){border-top-right-radius:unset;border-bottom-right-radius:unset}[dir="rtl"] :is(.ck.ck-splitbutton:hover>.ck-splitbutton__action, .ck.ck-splitbutton.ck-splitbutton_open>.ck-splitbutton__action){border-top-left-radius:unset;border-bottom-left-radius:unset}.ck.ck-splitbutton>.ck-splitbutton__arrow{min-width:unset}[dir="ltr"] :is(.ck.ck-splitbutton>.ck-splitbutton__arrow){border-top-left-radius:unset;border-bottom-left-radius:unset}[dir="rtl"] :is(.ck.ck-splitbutton>.ck-splitbutton__arrow){border-top-right-radius:unset;border-bottom-right-radius:unset}.ck.ck-splitbutton>.ck-splitbutton__arrow svg{width:var(--ck-dropdown-arrow-size)}.ck.ck-splitbutton>.ck-splitbutton__arrow:not(:focus){border-top-width:0;border-bottom-width:0}.ck.ck-splitbutton.ck-splitbutton_open{border-radius:var(--ck-rounded-corners-radius)}.ck.ck-splitbutton.ck-splitbutton_open>.ck-splitbutton__action{border-bottom-left-radius:0}.ck.ck-splitbutton.ck-splitbutton_open>.ck-splitbutton__arrow{border-bottom-right-radius:0}:is(.ck.ck-splitbutton.ck-splitbutton_open, .ck.ck-splitbutton:hover)>.ck-button:not(.ck-on):not(.ck-disabled):not(:hover){background:var(--ck-color-split-button-hover-background)}:is(.ck.ck-splitbutton.ck-splitbutton_open, .ck.ck-splitbutton:hover)>.ck-splitbutton__arrow:not(.ck-disabled):after{content:"";background-color:var(--ck-color-split-button-hover-border);width:1px;height:100%;position:absolute}:is(.ck.ck-splitbutton.ck-splitbutton_open, .ck.ck-splitbutton:hover)>.ck-splitbutton__arrow:focus:after{--ck-color-split-button-hover-border: var(--ck-color-focus-border)}[dir="ltr"] :is(.ck.ck-splitbutton.ck-splitbutton_open, .ck.ck-splitbutton:hover)>.ck-splitbutton__arrow:not(.ck-disabled):after{left:-1px}[dir="rtl"] :is(.ck.ck-splitbutton.ck-splitbutton_open, .ck.ck-splitbutton:hover)>.ck-splitbutton__arrow:not(.ck-disabled):after{right:-1px}.ck.ck-splitbutton{font-size:inherit}.ck.ck-toolbar-dropdown .ck-toolbar{border:0}:root{--ck-toolbar-dropdown-max-width: 60vw}.ck.ck-toolbar-dropdown>.ck-dropdown__panel{width:max-content;max-width:var(--ck-toolbar-dropdown-max-width)}.ck.ck-toolbar-dropdown>.ck-dropdown__panel .ck-button:focus{z-index:calc(var(--ck-z-default) + 1)}.ck.ck-dropdown>.ck-dropdown__panel>.ck-list{border-radius:var(--ck-rounded-corners-radius);border-top-left-radius:0}.ck.ck-dropdown>.ck-dropdown__panel>.ck-list .ck-list__item:first-child>.ck-button{border-radius:var(--ck-rounded-corners-radius);border-top-left-radius:0;border-bottom-right-radius:0;border-bottom-left-radius:0}.ck.ck-dropdown>.ck-dropdown__panel>.ck-list .ck-list__item:last-child>.ck-button{border-radius:var(--ck-rounded-corners-radius);border-top-left-radius:0;border-top-right-radius:0}.ck.ck-dropdown-menu-list__nested-menu{display:block}:root{--ck-dropdown-menu-menu-item-min-width: 18em}.ck.ck-dropdown-menu-list__nested-menu__item{min-width:var(--ck-dropdown-menu-menu-item-min-width)}.ck-button.ck-dropdown-menu-list__nested-menu__item__button{border-radius:0}.ck-button.ck-dropdown-menu-list__nested-menu__item__button>.ck-spinner-container,.ck-button.ck-dropdown-menu-list__nested-menu__item__button>.ck-spinner-container .ck-spinner{--ck-toolbar-spinner-size: 20px}.ck-button.ck-dropdown-menu-list__nested-menu__item__button>.ck-spinner-container{margin-left:calc(-1 * var(--ck-spacing-small));margin-right:var(--ck-spacing-small)}.ck-button.ck-dropdown-menu-list__nested-menu__item__button:focus{box-shadow:none;border-color:#0000}.ck-button.ck-dropdown-menu-list__nested-menu__item__button:focus:not(.ck-on){background:var(--ck-color-button-default-hover-background)}.ck.ck-button.ck-dropdown-menu-list__nested-menu__button{width:100%;padding:var(--ck-spacing-tiny) calc(2 * var(--ck-spacing-standard));border-radius:0}.ck.ck-button.ck-dropdown-menu-list__nested-menu__button:focus{box-shadow:none;border-color:#0000}.ck.ck-button.ck-dropdown-menu-list__nested-menu__button:focus:not(.ck-on){background:var(--ck-color-button-default-hover-background)}.ck.ck-button.ck-dropdown-menu-list__nested-menu__button>.ck-button__label{text-overflow:ellipsis;flex-grow:1;overflow:hidden}.ck.ck-button.ck-dropdown-menu-list__nested-menu__button.ck-disabled>.ck-button__label{opacity:var(--ck-disabled-opacity)}.ck.ck-button.ck-dropdown-menu-list__nested-menu__button.ck-icon-spacing:not(:has(.ck-button__icon))>.ck-button__label{margin-left:calc(var(--ck-icon-size) - var(--ck-spacing-small))}.ck.ck-button.ck-dropdown-menu-list__nested-menu__button>.ck-dropdown-menu-list__nested-menu__button__arrow{width:var(--ck-dropdown-arrow-size);pointer-events:none;z-index:var(--ck-z-default)}[dir="ltr"] :is(.ck.ck-button.ck-dropdown-menu-list__nested-menu__button>.ck-dropdown-menu-list__nested-menu__button__arrow){right:var(--ck-spacing-standard);margin-left:var(--ck-spacing-standard);margin-right:calc(-1 * var(--ck-spacing-small));transform:rotate(-90deg)}[dir="rtl"] :is(.ck.ck-button.ck-dropdown-menu-list__nested-menu__button>.ck-dropdown-menu-list__nested-menu__button__arrow){left:var(--ck-spacing-standard);margin-right:var(--ck-spacing-small);margin-left:calc(-1 * var(--ck-spacing-small));transform:rotate(90deg)}.ck.ck-button.ck-dropdown-menu-list__nested-menu__button.ck-disabled>.ck-dropdown-menu-list__nested-menu__button__arrow{opacity:var(--ck-disabled-opacity)}[dir="ltr"] .ck.ck-button.ck-dropdown-menu-list__nested-menu__button:not(.ck-button_with-text){padding-left:var(--ck-spacing-small)}[dir="rtl"] .ck.ck-button.ck-dropdown-menu-list__nested-menu__button:not(.ck-button_with-text){padding-right:var(--ck-spacing-small)}:root{--ck-dropdown-menu-menu-panel-max-width: 75vw}.ck.ck-balloon-panel.ck-dropdown-menu__nested-menu__panel{box-shadow:var(--ck-drop-shadow), 0 0;background:var(--ck-color-dropdown-panel-background);border:1px solid var(--ck-color-dropdown-panel-border);height:fit-content;max-width:var(--ck-dropdown-menu-menu-panel-max-width);max-height:314px;position:absolute;bottom:0;overflow-y:auto}.ck.ck-balloon-panel.ck-dropdown-menu__nested-menu__panel:after,.ck.ck-balloon-panel.ck-dropdown-menu__nested-menu__panel:before{display:none}.ck.ck-balloon-panel.ck-dropdown-menu__nested-menu__panel.ck-balloon-panel_es,.ck.ck-balloon-panel.ck-dropdown-menu__nested-menu__panel.ck-balloon-panel_se{border-top-left-radius:0}.ck.ck-balloon-panel.ck-dropdown-menu__nested-menu__panel.ck-balloon-panel_ws,.ck.ck-balloon-panel.ck-dropdown-menu__nested-menu__panel.ck-balloon-panel_sw{border-top-right-radius:0}.ck.ck-balloon-panel.ck-dropdown-menu__nested-menu__panel.ck-balloon-panel_en,.ck.ck-balloon-panel.ck-dropdown-menu__nested-menu__panel.ck-balloon-panel_ne{border-bottom-left-radius:0}.ck.ck-balloon-panel.ck-dropdown-menu__nested-menu__panel.ck-balloon-panel_wn,.ck.ck-balloon-panel.ck-dropdown-menu__nested-menu__panel.ck-balloon-panel_nw{border-bottom-right-radius:0}.ck.ck-balloon-panel.ck-dropdown-menu__nested-menu__panel:focus{outline:none}.ck.ck-balloon-panel.ck-dropdown-menu__nested-menu__panel{z-index:calc(var(--ck-z-panel) + 1)}:root{--ck-color-editable-blur-selection: #d9d9d9}.ck.ck-editor__top .ck-sticky-panel .ck-sticky-panel__content{border-radius:var(--ck-rounded-corners-radius);border:1px solid var(--ck-color-base-border);border-bottom-width:0;border-bottom-right-radius:0;border-bottom-left-radius:0}.ck.ck-editor__top .ck-sticky-panel .ck-sticky-panel__content.ck-sticky-panel__content_sticky{border-bottom-width:1px}.ck.ck-editor__top .ck-sticky-panel .ck-sticky-panel__content .ck-menu-bar{border:0;border-bottom:1px solid var(--ck-color-base-border)}.ck.ck-editor__top .ck-sticky-panel .ck-sticky-panel__content .ck-toolbar{border:0}.ck.ck-editor__editable:not(.ck-editor__nested-editable){border-radius:var(--ck-rounded-corners-radius)}.ck.ck-editor__editable:not(.ck-editor__nested-editable).ck-focused{border:var(--ck-focus-ring);box-shadow:var(--ck-inner-shadow), 0 0;outline:none}.ck.ck-editor__editable_inline{padding:0 var(--ck-spacing-standard);border:1px solid #0000;overflow:auto}.ck.ck-editor__editable_inline[dir="ltr"]{text-align:left}.ck.ck-editor__editable_inline[dir="rtl"]{text-align:right}.ck.ck-editor__editable_inline>:first-child{margin-top:var(--ck-spacing-large)}.ck.ck-editor__editable_inline>:last-child{margin-bottom:var(--ck-spacing-large)}.ck.ck-editor__editable_inline.ck-blurred ::selection{background:var(--ck-color-editable-blur-selection)}.ck.ck-balloon-panel.ck-toolbar-container[class*="arrow_n"]:after{border-bottom-color:var(--ck-color-panel-background)}.ck.ck-balloon-panel.ck-toolbar-container[class*="arrow_s"]:after{border-top-color:var(--ck-color-panel-background)}.ck.ck-form__row{padding:var(--ck-spacing-standard) var(--ck-spacing-large) 0;flex-direction:row;justify-content:space-between;align-items:flex-start;display:flex}.ck.ck-form__row.ck-form__row_large-top-padding{padding-top:var(--ck-spacing-large)}.ck.ck-form__row.ck-form__row_large-bottom-padding{padding-bottom:var(--ck-spacing-large)}.ck.ck-form__row.ck-form__row_with-submit{flex-wrap:nowrap}.ck.ck-form__row.ck-form__row_with-submit>:not(:first-child){margin-inline-start:var(--ck-spacing-standard)}.ck.ck-form__row>.ck.ck-form__row{padding:0}:root{--ck-form-header-height: 3.384em}.ck.ck-form__header{padding:var(--ck-spacing-small) var(--ck-spacing-large);height:var(--ck-form-header-height);line-height:var(--ck-form-header-height);border-bottom:1px solid var(--ck-color-base-border);flex-flow:row;flex-shrink:0;justify-content:space-between;align-items:center;display:flex}.ck.ck-form__header>.ck-icon{flex-shrink:0;margin-inline-end:var(--ck-spacing-medium)}.ck.ck-form__header .ck-form__header__label{--ck-font-size-base: 1.153em;font-weight:bold}.ck.ck-form__header:has(.ck-button-back.ck-hidden){padding-inline:var(--ck-spacing-large) var(--ck-spacing-large)}.ck.ck-form__header:has(.ck-button-back:not(.ck-hidden)){padding-inline:var(--ck-spacing-small) var(--ck-spacing-small)}.ck.ck-form__header>.ck-button-back{margin-inline-end:var(--ck-spacing-small)}.ck.ck-form__header>.ck.ck-button{flex-shrink:0}.ck.ck-form__header h2.ck-form__header__label{text-overflow:ellipsis;flex-grow:1;overflow:hidden}:root{--ck-icon-size: calc(var(--ck-line-height-base) * var(--ck-font-size-normal));--ck-icon-font-size: .833335em}.ck.ck-icon{width:var(--ck-icon-size);height:var(--ck-icon-size);font-size:var(--ck-icon-font-size);cursor:inherit}.ck.ck-icon *{cursor:inherit}.ck.ck-icon.ck-icon_inherit-color{color:inherit}.ck.ck-icon.ck-icon_inherit-color *{color:inherit}.ck.ck-icon.ck-icon_inherit-color *:not([fill]){fill:currentColor}.ck.ck-icon{vertical-align:middle}:root{--ck-input-width: 18em;--ck-input-text-width: var(--ck-input-width)}.ck.ck-input{border-radius:var(--ck-rounded-corners-radius);background:var(--ck-color-input-background);border:1px solid var(--ck-color-input-border);padding:var(--ck-spacing-extra-tiny) var(--ck-spacing-medium);min-width:var(--ck-input-width);min-height:var(--ck-ui-component-min-height);transition:box-shadow 0.1s ease-in-out, border 0.1s ease-in-out}@media (prefers-reduced-motion:reduce){.ck.ck-input{transition:none}}.ck.ck-input:focus{border:var(--ck-focus-ring);box-shadow:var(--ck-focus-outer-shadow), 0 0;outline:none}.ck.ck-input[readonly]{border:1px solid var(--ck-color-input-disabled-border);background:var(--ck-color-input-disabled-background);color:var(--ck-color-input-disabled-text)}.ck.ck-input[readonly]:focus{box-shadow:var(--ck-focus-disabled-outer-shadow), 0 0}.ck.ck-input.ck-error{border-color:var(--ck-color-input-error-border);animation:0.3s both ck-input-shake}@media (prefers-reduced-motion:reduce){.ck.ck-input.ck-error{animation:none}}.ck.ck-input.ck-error:focus{box-shadow:var(--ck-focus-error-outer-shadow), 0 0}@keyframes ck-input-shake{20%{transform:translateX(-2px)}40%{transform:translateX(2px)}60%{transform:translateX(-1px)}80%{transform:translateX(1px)}}.ck-textarea{overflow-x:hidden}.ck.ck-label{font-weight:bold;display:block}.ck.ck-voice-label{display:none}:root{--ck-labeled-field-view-transition: .1s cubic-bezier(0, 0, .24, .95);--ck-labeled-field-empty-unfocused-max-width: 100% - 2 * var(--ck-spacing-medium);--ck-labeled-field-label-default-position-x: var(--ck-spacing-medium);--ck-labeled-field-label-default-position-y: calc(.6 * var(--ck-font-size-base));--ck-color-labeled-field-label-background: var(--ck-color-base-background)}.ck.ck-labeled-field-view{border-radius:var(--ck-rounded-corners-radius)}.ck.ck-labeled-field-view .ck.ck-label{display:block;position:absolute}.ck.ck-labeled-field-view>.ck.ck-labeled-field-view__input-wrapper{width:100%;display:flex}.ck.ck-labeled-field-view>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label{pointer-events:none;background:var(--ck-color-labeled-field-label-background);padding:0 calc(.5 * var(--ck-font-size-tiny));line-height:initial;text-overflow:ellipsis;max-width:100%;transition:transform var(--ck-labeled-field-view-transition), padding var(--ck-labeled-field-view-transition), background var(--ck-labeled-field-view-transition);font-weight:normal;top:0;overflow:hidden}[dir="ltr"] :is(.ck.ck-labeled-field-view>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label){transform-origin:0 0;transform:translate(var(--ck-spacing-medium), -6px) scale(0.75);left:0}[dir="rtl"] :is(.ck.ck-labeled-field-view>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label){transform-origin:100% 0;transform:translate(calc(-1 * var(--ck-spacing-medium)), -6px) scale(0.75);right:0}@media (prefers-reduced-motion:reduce){.ck.ck-labeled-field-view>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label{transition:none}}.ck.ck-labeled-field-view>.ck.ck-labeled-field-view__input-wrapper{position:relative}.ck.ck-labeled-field-view.ck-error>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label,.ck.ck-labeled-field-view.ck-error .ck-input:not([readonly])+.ck.ck-label{color:var(--ck-color-base-error)}.ck.ck-labeled-field-view .ck-labeled-field-view__status{font-size:var(--ck-font-size-small);margin-top:var(--ck-spacing-small);white-space:normal}.ck.ck-labeled-field-view .ck-labeled-field-view__status.ck-labeled-field-view__status_error{color:var(--ck-color-base-error)}.ck.ck-labeled-field-view.ck-disabled>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label,.ck.ck-labeled-field-view.ck-labeled-field-view_empty:not(.ck-labeled-field-view_focused)>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label{color:var(--ck-color-input-disabled-text)}[dir="ltr"] :is(.ck.ck-labeled-field-view.ck-disabled.ck-labeled-field-view_empty:not(.ck-labeled-field-view_placeholder)>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label, .ck.ck-labeled-field-view.ck-labeled-field-view_empty:not(.ck-labeled-field-view_focused):not(.ck-labeled-field-view_placeholder):not(.ck-error)>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label){transform:translate(var(--ck-labeled-field-label-default-position-x), var(--ck-labeled-field-label-default-position-y)) scale(1)}[dir="rtl"] :is(.ck.ck-labeled-field-view.ck-disabled.ck-labeled-field-view_empty:not(.ck-labeled-field-view_placeholder)>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label, .ck.ck-labeled-field-view.ck-labeled-field-view_empty:not(.ck-labeled-field-view_focused):not(.ck-labeled-field-view_placeholder):not(.ck-error)>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label){transform:translate(calc(-1 * var(--ck-labeled-field-label-default-position-x)), var(--ck-labeled-field-label-default-position-y)) scale(1)}.ck.ck-labeled-field-view.ck-disabled.ck-labeled-field-view_empty:not(.ck-labeled-field-view_placeholder)>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label,.ck.ck-labeled-field-view.ck-labeled-field-view_empty:not(.ck-labeled-field-view_focused):not(.ck-labeled-field-view_placeholder):not(.ck-error)>.ck.ck-labeled-field-view__input-wrapper>.ck.ck-label{max-width:calc(var(--ck-labeled-field-empty-unfocused-max-width));background:none;padding:0}.ck.ck-labeled-field-view>.ck.ck-labeled-field-view__input-wrapper>.ck-dropdown>.ck.ck-button{background:none}.ck.ck-labeled-field-view.ck-labeled-field-view_empty>.ck.ck-labeled-field-view__input-wrapper>.ck-dropdown>.ck-button>.ck-button__label{opacity:0}.ck.ck-labeled-field-view.ck-labeled-field-view_empty:not(.ck-labeled-field-view_focused):not(.ck-labeled-field-view_placeholder)>.ck.ck-labeled-field-view__input-wrapper>.ck-dropdown+.ck-label{max-width:calc(var(--ck-labeled-field-empty-unfocused-max-width) - var(--ck-dropdown-arrow-size) - var(--ck-spacing-standard))}.ck.ck-labeled-field-view.ck-labeled-field-view_full-width{flex-grow:1}.ck.ck-labeled-input .ck-labeled-input__status{font-size:var(--ck-font-size-small);margin-top:var(--ck-spacing-small);white-space:normal}.ck.ck-labeled-input .ck-labeled-input__status_error{color:var(--ck-color-base-error)}.ck.ck-list{border-radius:var(--ck-rounded-corners-radius);background:var(--ck-color-list-background);padding:var(--ck-spacing-small) 0;-webkit-user-select:none;user-select:none;flex-direction:column;list-style-type:none;display:flex}.ck.ck-list .ck-list__item,.ck.ck-list .ck-list__separator{display:block}.ck.ck-list .ck-list__item>:focus{z-index:var(--ck-z-default);position:relative}.ck.ck-list__item{cursor:default;min-width:15em}.ck.ck-list__item>.ck-button:not(.ck-list-item-button){padding:var(--ck-spacing-tiny) calc(2 * var(--ck-spacing-standard));min-height:unset;border-radius:0;width:100%}[dir="ltr"] :is(.ck.ck-list__item>.ck-button:not(.ck-list-item-button)){text-align:left}[dir="rtl"] :is(.ck.ck-list__item>.ck-button:not(.ck-list-item-button)){text-align:right}.ck.ck-list__item>.ck-button:not(.ck-list-item-button) .ck-button__label{line-height:calc(var(--ck-line-height-base) * var(--ck-font-size-base))}.ck.ck-list__item>.ck-button:not(.ck-list-item-button):active{box-shadow:none}.ck.ck-list__item>.ck-button:not(.ck-list-item-button).ck-on{background:var(--ck-color-list-button-on-background);color:var(--ck-color-list-button-on-text)}.ck.ck-list__item>.ck-button:not(.ck-list-item-button).ck-on:active{box-shadow:none}.ck.ck-list__item>.ck-button:not(.ck-list-item-button).ck-on:hover:not(.ck-disabled){background:var(--ck-color-list-button-on-background-focus)}.ck.ck-list__item>.ck-button:not(.ck-list-item-button).ck-on:focus:not(.ck-disabled){border-color:var(--ck-color-base-background)}.ck.ck-list__item>.ck-button:not(.ck-list-item-button):hover:not(.ck-disabled){background:var(--ck-color-list-button-hover-background)}.ck.ck-list__item>.ck-button.ck-switchbutton.ck-on{background:var(--ck-color-list-background);color:inherit}.ck.ck-list__item>.ck-button.ck-switchbutton.ck-on:hover:not(.ck-disabled){background:var(--ck-color-list-button-hover-background);color:inherit}.ck-list .ck-list__group{padding-top:var(--ck-spacing-medium)}.ck-list .ck-list__group:first-child{padding-top:0}:not(.ck-hidden)~:is(.ck-list .ck-list__group){border-top:1px solid var(--ck-color-base-border)}.ck-list .ck-list__group>.ck-label{padding:var(--ck-spacing-medium) var(--ck-spacing-large) 0;font-size:11px;font-weight:bold}.ck.ck-list__separator{background:var(--ck-color-base-border);width:100%;height:1px;margin:var(--ck-spacing-small) 0}:root{--ck-balloon-border-width: 1px;--ck-balloon-arrow-offset: 2px;--ck-balloon-arrow-height: 10px;--ck-balloon-arrow-half-width: 8px;--ck-balloon-arrow-drop-shadow: 0 2px 2px var(--ck-color-shadow-drop);--ck-balloon-panel-arrow-z-index: calc(var(--ck-z-default) - 3)}.ck.ck-balloon-panel{border-radius:var(--ck-rounded-corners-radius);box-shadow:var(--ck-drop-shadow), 0 0;background:var(--ck-color-panel-background);border:var(--ck-balloon-border-width) solid var(--ck-color-panel-border);min-height:15px;z-index:var(--ck-z-panel);display:none;position:absolute}.ck.ck-balloon-panel.ck-balloon-panel_with-arrow:before,.ck.ck-balloon-panel.ck-balloon-panel_with-arrow:after{content:"";border-style:solid;width:0;height:0;position:absolute}.ck.ck-balloon-panel.ck-balloon-panel_with-arrow:before{z-index:var(--ck-balloon-panel-arrow-z-index)}.ck.ck-balloon-panel.ck-balloon-panel_with-arrow:after{z-index:calc(var(--ck-balloon-panel-arrow-z-index) + 1)}.ck.ck-balloon-panel[class*="arrow_n"]:before,.ck.ck-balloon-panel[class*="arrow_n"]:after{border-width:0 var(--ck-balloon-arrow-half-width) var(--ck-balloon-arrow-height) var(--ck-balloon-arrow-half-width)}.ck.ck-balloon-panel[class*="arrow_n"]:before{border-color:transparent transparent var(--ck-color-panel-border) transparent;margin-top:calc(-1 * var(--ck-balloon-border-width));z-index:var(--ck-balloon-panel-arrow-z-index)}.ck.ck-balloon-panel[class*="arrow_n"]:after{border-color:transparent transparent var(--ck-color-panel-background) transparent;margin-top:calc(var(--ck-balloon-arrow-offset) - var(--ck-balloon-border-width));z-index:calc(var(--ck-balloon-panel-arrow-z-index) + 1)}.ck.ck-balloon-panel[class*="arrow_s"]:before,.ck.ck-balloon-panel[class*="arrow_s"]:after{border-width:var(--ck-balloon-arrow-height) var(--ck-balloon-arrow-half-width) 0 var(--ck-balloon-arrow-half-width)}.ck.ck-balloon-panel[class*="arrow_s"]:before{border-color:var(--ck-color-panel-border) transparent transparent;filter:drop-shadow(var(--ck-balloon-arrow-drop-shadow));margin-bottom:calc(-1 * var(--ck-balloon-border-width));z-index:var(--ck-balloon-panel-arrow-z-index)}.ck.ck-balloon-panel[class*="arrow_s"]:after{border-color:var(--ck-color-panel-background) transparent transparent transparent;margin-bottom:calc(var(--ck-balloon-arrow-offset) - var(--ck-balloon-border-width));z-index:calc(var(--ck-balloon-panel-arrow-z-index) + 1)}.ck.ck-balloon-panel[class*="arrow_e"]:before,.ck.ck-balloon-panel[class*="arrow_e"]:after{border-width:var(--ck-balloon-arrow-half-width) 0 var(--ck-balloon-arrow-half-width) var(--ck-balloon-arrow-height)}.ck.ck-balloon-panel[class*="arrow_e"]:before{border-color:transparent transparent transparent var(--ck-color-panel-border);margin-right:calc(-1 * var(--ck-balloon-border-width))}.ck.ck-balloon-panel[class*="arrow_e"]:after{border-color:transparent transparent transparent var(--ck-color-panel-background);margin-right:calc(var(--ck-balloon-arrow-offset) - var(--ck-balloon-border-width))}.ck.ck-balloon-panel[class*="arrow_w"]:before,.ck.ck-balloon-panel[class*="arrow_w"]:after{border-width:var(--ck-balloon-arrow-half-width) var(--ck-balloon-arrow-height) var(--ck-balloon-arrow-half-width) 0}.ck.ck-balloon-panel[class*="arrow_w"]:before{border-color:transparent var(--ck-color-panel-border) transparent transparent;margin-left:calc(-1 * var(--ck-balloon-border-width))}.ck.ck-balloon-panel[class*="arrow_w"]:after{border-color:transparent var(--ck-color-panel-background) transparent transparent;margin-left:calc(var(--ck-balloon-arrow-offset) - var(--ck-balloon-border-width))}.ck.ck-balloon-panel.ck-balloon-panel_arrow_n:before,.ck.ck-balloon-panel.ck-balloon-panel_arrow_n:after{margin-left:calc(-1 * var(--ck-balloon-arrow-half-width));left:50%;top:calc(-1 * var(--ck-balloon-arrow-height))}.ck.ck-balloon-panel.ck-balloon-panel_arrow_nw:before,.ck.ck-balloon-panel.ck-balloon-panel_arrow_nw:after{left:calc(2 * var(--ck-balloon-arrow-half-width));top:calc(-1 * var(--ck-balloon-arrow-height))}.ck.ck-balloon-panel.ck-balloon-panel_arrow_ne:before,.ck.ck-balloon-panel.ck-balloon-panel_arrow_ne:after{right:calc(2 * var(--ck-balloon-arrow-half-width));top:calc(-1 * var(--ck-balloon-arrow-height))}.ck.ck-balloon-panel.ck-balloon-panel_arrow_s:before,.ck.ck-balloon-panel.ck-balloon-panel_arrow_s:after{margin-left:calc(-1 * var(--ck-balloon-arrow-half-width));left:50%;bottom:calc(-1 * var(--ck-balloon-arrow-height))}.ck.ck-balloon-panel.ck-balloon-panel_arrow_sw:before,.ck.ck-balloon-panel.ck-balloon-panel_arrow_sw:after{left:calc(2 * var(--ck-balloon-arrow-half-width));bottom:calc(-1 * var(--ck-balloon-arrow-height))}.ck.ck-balloon-panel.ck-balloon-panel_arrow_se:before,.ck.ck-balloon-panel.ck-balloon-panel_arrow_se:after{right:calc(2 * var(--ck-balloon-arrow-half-width));bottom:calc(-1 * var(--ck-balloon-arrow-height))}.ck.ck-balloon-panel.ck-balloon-panel_arrow_sme:before,.ck.ck-balloon-panel.ck-balloon-panel_arrow_sme:after{margin-right:calc(2 * var(--ck-balloon-arrow-half-width));right:25%;bottom:calc(-1 * var(--ck-balloon-arrow-height))}.ck.ck-balloon-panel.ck-balloon-panel_arrow_smw:before,.ck.ck-balloon-panel.ck-balloon-panel_arrow_smw:after{margin-left:calc(2 * var(--ck-balloon-arrow-half-width));left:25%;bottom:calc(-1 * var(--ck-balloon-arrow-height))}.ck.ck-balloon-panel.ck-balloon-panel_arrow_nme:before,.ck.ck-balloon-panel.ck-balloon-panel_arrow_nme:after{margin-right:calc(2 * var(--ck-balloon-arrow-half-width));right:25%;top:calc(-1 * var(--ck-balloon-arrow-height))}.ck.ck-balloon-panel.ck-balloon-panel_arrow_nmw:before,.ck.ck-balloon-panel.ck-balloon-panel_arrow_nmw:after{margin-left:calc(2 * var(--ck-balloon-arrow-half-width));left:25%;top:calc(-1 * var(--ck-balloon-arrow-height))}.ck.ck-balloon-panel.ck-balloon-panel_arrow_e:before,.ck.ck-balloon-panel.ck-balloon-panel_arrow_e:after{right:calc(-1 * var(--ck-balloon-arrow-height));margin-top:calc(-1 * var(--ck-balloon-arrow-half-width));top:50%}.ck.ck-balloon-panel.ck-balloon-panel_arrow_w:before,.ck.ck-balloon-panel.ck-balloon-panel_arrow_w:after{left:calc(-1 * var(--ck-balloon-arrow-height));margin-top:calc(-1 * var(--ck-balloon-arrow-half-width));top:50%}.ck.ck-balloon-panel.ck-balloon-panel_visible{display:block}.ck .ck-balloon-rotator__navigation{background:var(--ck-color-toolbar-background);border-bottom:1px solid var(--ck-color-toolbar-border);padding:0 var(--ck-spacing-small);align-items:center;display:flex}.ck .ck-balloon-rotator__navigation>*{margin-right:var(--ck-spacing-small);margin-top:var(--ck-spacing-small);margin-bottom:var(--ck-spacing-small)}.ck .ck-balloon-rotator__navigation .ck-balloon-rotator__counter{margin-right:var(--ck-spacing-standard);margin-left:var(--ck-spacing-small)}.ck .ck-balloon-rotator__navigation{justify-content:center}.ck .ck-balloon-rotator__content .ck.ck-annotation-wrapper{box-shadow:none}.ck .ck-balloon-rotator__content .ck-toolbar{justify-content:center}:root{--ck-balloon-fake-panel-offset-horizontal: 6px;--ck-balloon-fake-panel-offset-vertical: 6px}.ck .ck-fake-panel div{box-shadow:var(--ck-drop-shadow), 0 0;background:var(--ck-color-panel-background);border:1px solid var(--ck-color-panel-border);border-radius:var(--ck-border-radius);width:100%;height:100%;min-height:15px;position:absolute}.ck .ck-fake-panel div:first-child{margin-left:var(--ck-balloon-fake-panel-offset-horizontal);margin-top:var(--ck-balloon-fake-panel-offset-vertical);z-index:2}.ck .ck-fake-panel div:nth-child(2){margin-left:calc(var(--ck-balloon-fake-panel-offset-horizontal) * 2);margin-top:calc(var(--ck-balloon-fake-panel-offset-vertical) * 2);z-index:1}.ck .ck-fake-panel div:nth-child(3){margin-left:calc(var(--ck-balloon-fake-panel-offset-horizontal) * 3);margin-top:calc(var(--ck-balloon-fake-panel-offset-vertical) * 3)}.ck .ck-fake-panel{z-index:calc(var(--ck-z-panel) - 1);position:absolute}.ck .ck-balloon-panel_arrow_s+.ck-fake-panel,.ck .ck-balloon-panel_arrow_se+.ck-fake-panel,.ck .ck-balloon-panel_arrow_sw+.ck-fake-panel{--ck-balloon-fake-panel-offset-vertical: -6px}.ck.ck-sticky-panel .ck-sticky-panel__content_sticky{box-shadow:var(--ck-drop-shadow), 0 0;z-index:var(--ck-z-panel);border-width:0 1px 1px;border-top-left-radius:0;border-top-right-radius:0;position:fixed;top:0}.ck.ck-sticky-panel .ck-sticky-panel__content_sticky_bottom-limit{position:absolute;top:auto}.ck.ck-autocomplete>.ck-search__results{border-radius:var(--ck-rounded-corners-radius);box-shadow:var(--ck-drop-shadow), 0 0;background:var(--ck-color-base-background);border:1px solid var(--ck-color-dropdown-panel-border);min-width:auto;max-height:200px;position:absolute;overflow-y:auto}.ck.ck-autocomplete>.ck-search__results.ck-search__results_n{border-bottom-right-radius:0;border-bottom-left-radius:0;margin-bottom:-1px;bottom:100%}.ck.ck-autocomplete>.ck-search__results.ck-search__results_s{border-top-left-radius:0;border-top-right-radius:0;margin-top:-1px;top:100%;bottom:auto}.ck.ck-autocomplete>.ck-search__results{z-index:var(--ck-z-panel)}.ck.ck-autocomplete{position:relative}:root{--ck-search-field-view-horizontal-spacing: calc(var(--ck-icon-size) + var(--ck-spacing-medium))}.ck.ck-search>.ck-labeled-field-view .ck-input{width:100%}.ck.ck-search>.ck-labeled-field-view>.ck-labeled-field-view__input-wrapper>.ck-icon{position:absolute;top:50%;transform:translateY(-50%)}[dir="ltr"] :is(.ck.ck-search>.ck-labeled-field-view>.ck-labeled-field-view__input-wrapper>.ck-icon){left:var(--ck-spacing-medium)}[dir="rtl"] :is(.ck.ck-search>.ck-labeled-field-view>.ck-labeled-field-view__input-wrapper>.ck-icon){right:var(--ck-spacing-medium)}.ck.ck-search>.ck-labeled-field-view .ck-search__reset{position:absolute;top:50%;transform:translateY(-50%)}.ck.ck-search>.ck-labeled-field-view.ck-search__query_with-icon{--ck-labeled-field-label-default-position-x: var(--ck-search-field-view-horizontal-spacing)}.ck.ck-search>.ck-labeled-field-view.ck-search__query_with-icon>.ck-labeled-field-view__input-wrapper>.ck-icon{opacity:0.5;pointer-events:none}.ck.ck-search>.ck-labeled-field-view.ck-search__query_with-icon .ck-input{width:100%}[dir="ltr"] :is(.ck.ck-search>.ck-labeled-field-view.ck-search__query_with-icon .ck-input){padding-left:var(--ck-search-field-view-horizontal-spacing)}[dir="rtl"] :is(.ck.ck-search>.ck-labeled-field-view.ck-search__query_with-icon .ck-input):not(.ck-input-text_empty){padding-left:var(--ck-search-field-view-horizontal-spacing)}.ck.ck-search>.ck-labeled-field-view.ck-search__query_with-reset{--ck-labeled-field-empty-unfocused-max-width: 100% - 2 * var(--ck-search-field-view-horizontal-spacing)}.ck.ck-search>.ck-labeled-field-view.ck-search__query_with-reset.ck-labeled-field-view_empty{--ck-labeled-field-empty-unfocused-max-width: 100% - var(--ck-search-field-view-horizontal-spacing) - var(--ck-spacing-medium)}.ck.ck-search>.ck-labeled-field-view.ck-search__query_with-reset .ck-search__reset{opacity:0.5;background:none;min-width:auto;min-height:auto;padding:0}[dir="ltr"] :is(.ck.ck-search>.ck-labeled-field-view.ck-search__query_with-reset .ck-search__reset){right:var(--ck-spacing-medium)}[dir="rtl"] :is(.ck.ck-search>.ck-labeled-field-view.ck-search__query_with-reset .ck-search__reset){left:var(--ck-spacing-medium)}.ck.ck-search>.ck-labeled-field-view.ck-search__query_with-reset .ck-search__reset:hover{opacity:1}.ck.ck-search>.ck-labeled-field-view.ck-search__query_with-reset .ck-input{width:100%}[dir="ltr"] :is(.ck.ck-search>.ck-labeled-field-view.ck-search__query_with-reset .ck-input):not(.ck-input-text_empty){padding-right:var(--ck-search-field-view-horizontal-spacing)}[dir="rtl"] :is(.ck.ck-search>.ck-labeled-field-view.ck-search__query_with-reset .ck-input){padding-right:var(--ck-search-field-view-horizontal-spacing)}.ck.ck-search>.ck-search__results{min-width:100%}.ck.ck-search>.ck-search__results>.ck-search__info{width:100%;padding:var(--ck-spacing-medium) var(--ck-spacing-large)}.ck.ck-search>.ck-search__results>.ck-search__info *{white-space:normal}.ck.ck-search>.ck-search__results>.ck-search__info>span:first-child{font-weight:bold;display:block}.ck.ck-search>.ck-search__results>.ck-search__info>span:last-child{margin-top:var(--ck-spacing-medium)}.ck.ck-search>.ck-search__results>.ck-search__info:not(.ck-hidden)~*{display:none}.ck.ck-highlighted-text mark{background:var(--ck-color-highlight-background);vertical-align:initial;font-weight:inherit;line-height:inherit;font-size:inherit}.ck.ck-balloon-panel.ck-tooltip{--ck-balloon-border-width: 0px;--ck-balloon-arrow-offset: 0px;--ck-balloon-arrow-half-width: 4px;--ck-balloon-arrow-height: 4px;--ck-tooltip-text-padding: 4px;--ck-color-panel-background: var(--ck-color-tooltip-background);padding:0 var(--ck-spacing-medium);box-shadow:none;-webkit-user-select:none;user-select:none}.ck.ck-balloon-panel.ck-tooltip .ck-tooltip__text{color:var(--ck-color-tooltip-text);font-size:0.9em;line-height:1.5}.ck.ck-balloon-panel.ck-tooltip.ck-tooltip_multi-line .ck-tooltip__text{white-space:break-spaces;padding:var(--ck-tooltip-text-padding) 0;max-width:200px;display:inline-block}.ck.ck-balloon-panel.ck-tooltip:before{display:none}.ck.ck-balloon-panel.ck-tooltip{z-index:calc(var(--ck-z-dialog) + 100)}:root{--ck-toolbar-spinner-size: 18px}.ck.ck-spinner-container{width:var(--ck-toolbar-spinner-size);height:var(--ck-toolbar-spinner-size);animation:1.5s linear infinite ck-spinner-rotate;display:block}@media (prefers-reduced-motion:reduce){.ck.ck-spinner-container{animation-duration:3s}}.ck.ck-spinner-container{position:relative}.ck.ck-spinner{width:var(--ck-toolbar-spinner-size);height:var(--ck-toolbar-spinner-size);border:2px solid var(--ck-color-text);z-index:1;border-top-color:#0000;border-radius:50%;margin:0 auto;position:absolute;top:50%;left:0;right:0;transform:translateY(-50%)}@keyframes ck-spinner-rotate{to{transform:rotate(360deg)}}.ck.ck-toolbar{border-radius:var(--ck-rounded-corners-radius);background:var(--ck-color-toolbar-background);padding:0 var(--ck-spacing-small);border:1px solid var(--ck-color-toolbar-border);-webkit-user-select:none;user-select:none;flex-flow:row;align-items:center;display:flex}.ck.ck-toolbar .ck.ck-toolbar__separator{height:var(--ck-icon-size);background:var(--ck-color-toolbar-border);width:1px;min-width:1px;margin-top:var(--ck-spacing-small);margin-bottom:var(--ck-spacing-small);display:inline-block}.ck.ck-toolbar .ck.ck-toolbar__separator:first-child,.ck.ck-toolbar .ck.ck-toolbar__separator:last-child{display:none}.ck.ck-toolbar .ck-toolbar__line-break{flex-basis:100%;height:0}.ck.ck-toolbar>.ck-toolbar__items>:not(.ck-toolbar__line-break){margin-right:var(--ck-spacing-small)}.ck.ck-toolbar>.ck-toolbar__items:empty+.ck.ck-toolbar__separator{display:none}.ck.ck-toolbar>.ck-toolbar__items{flex-flow:wrap;flex-grow:1;align-items:center;display:flex}.ck.ck-toolbar>.ck-toolbar__items>:not(.ck-toolbar__line-break),.ck.ck-toolbar>.ck.ck-toolbar__grouped-dropdown{margin-top:var(--ck-spacing-small);margin-bottom:var(--ck-spacing-small)}.ck.ck-toolbar.ck-toolbar_vertical{padding:0}.ck.ck-toolbar.ck-toolbar_vertical>.ck-toolbar__items>.ck{border-radius:0;width:100%;margin:0}.ck.ck-toolbar.ck-toolbar_compact{padding:0}.ck.ck-toolbar.ck-toolbar_compact>.ck-toolbar__items>*{margin:0}.ck.ck-toolbar.ck-toolbar_compact>.ck-toolbar__items>*:not(:first-child):not(:last-child){border-radius:0}.ck.ck-toolbar>.ck.ck-toolbar__grouped-dropdown>.ck.ck-button.ck-dropdown__button{padding-left:var(--ck-spacing-tiny)}.ck.ck-toolbar>.ck.ck-toolbar__grouped-dropdown>.ck-dropdown__button .ck-dropdown__arrow{display:none}.ck.ck-toolbar .ck-toolbar__nested-toolbar-dropdown>.ck-dropdown__panel{min-width:auto}.ck.ck-toolbar .ck-toolbar__nested-toolbar-dropdown>.ck-button>.ck-button__label{width:auto;max-width:7em}.ck.ck-toolbar:focus{outline:none}.ck-toolbar-container .ck.ck-toolbar{border:0}.ck.ck-toolbar.ck-toolbar_grouping>.ck-toolbar__items{flex-wrap:nowrap}.ck.ck-toolbar.ck-toolbar_vertical>.ck-toolbar__items{flex-direction:column}.ck.ck-toolbar.ck-toolbar_floating>.ck-toolbar__items{flex-wrap:nowrap}:is([dir="rtl"] .ck.ck-toolbar, .ck.ck-toolbar[dir="rtl"])>.ck-toolbar__items>.ck{margin-right:0}:is([dir="rtl"] .ck.ck-toolbar, .ck.ck-toolbar[dir="rtl"]):not(.ck-toolbar_compact)>.ck-toolbar__items>.ck{margin-left:var(--ck-spacing-small)}:is([dir="rtl"] .ck.ck-toolbar, .ck.ck-toolbar[dir="rtl"])>.ck-toolbar__items>.ck:last-child{margin-left:0}:is([dir="rtl"] .ck.ck-toolbar, .ck.ck-toolbar[dir="rtl"]).ck-toolbar_compact>.ck-toolbar__items>.ck:first-child{border-top-left-radius:0;border-bottom-left-radius:0}:is([dir="rtl"] .ck.ck-toolbar, .ck.ck-toolbar[dir="rtl"]).ck-toolbar_compact>.ck-toolbar__items>.ck:last-child{border-top-right-radius:0;border-bottom-right-radius:0}:is([dir="rtl"] .ck.ck-toolbar, .ck.ck-toolbar[dir="rtl"])>.ck.ck-toolbar__separator,:is([dir="rtl"] .ck.ck-toolbar, .ck.ck-toolbar[dir="rtl"]).ck-toolbar_grouping>.ck-toolbar__items:not(:empty):not(:only-child){margin-left:var(--ck-spacing-small)}:is([dir="ltr"] .ck.ck-toolbar, .ck.ck-toolbar[dir="ltr"])>.ck-toolbar__items>.ck:last-child{margin-right:0}:is([dir="ltr"] .ck.ck-toolbar, .ck.ck-toolbar[dir="ltr"]).ck-toolbar_compact>.ck-toolbar__items>.ck:first-child{border-top-right-radius:0;border-bottom-right-radius:0}:is([dir="ltr"] .ck.ck-toolbar, .ck.ck-toolbar[dir="ltr"]).ck-toolbar_compact>.ck-toolbar__items>.ck:last-child{border-top-left-radius:0;border-bottom-left-radius:0}:is([dir="ltr"] .ck.ck-toolbar, .ck.ck-toolbar[dir="ltr"])>.ck.ck-toolbar__separator,:is([dir="ltr"] .ck.ck-toolbar, .ck.ck-toolbar[dir="ltr"]).ck-toolbar_grouping>.ck-toolbar__items:not(:empty):not(:only-child){margin-right:var(--ck-spacing-small)}:root{--ck-color-block-toolbar-button: var(--ck-color-text);--ck-block-toolbar-button-size: var(--ck-font-size-normal)}.ck.ck-block-toolbar-button{color:var(--ck-color-block-toolbar-button);font-size:var(--ck-block-toolbar-size);z-index:var(--ck-z-default);position:absolute}.ck.ck-menu-bar{background:var(--ck-color-base-background);padding:var(--ck-spacing-small);justify-content:flex-start;gap:var(--ck-spacing-small);border:1px solid var(--ck-color-toolbar-border);flex-wrap:wrap;width:100%;display:flex}.ck.ck-menu-bar__menu>.ck-menu-bar__menu__button{width:100%}.ck.ck-menu-bar__menu>.ck-menu-bar__menu__button>.ck-button__label{text-overflow:ellipsis;flex-grow:1;overflow:hidden}.ck.ck-menu-bar__menu>.ck-menu-bar__menu__button.ck-disabled>.ck-button__label{opacity:var(--ck-disabled-opacity)}[dir="ltr"] :is(.ck.ck-menu-bar__menu>.ck-menu-bar__menu__button):not(.ck-button_with-text){padding-left:var(--ck-spacing-small)}[dir="rtl"] :is(.ck.ck-menu-bar__menu>.ck-menu-bar__menu__button):not(.ck-button_with-text){padding-right:var(--ck-spacing-small)}.ck.ck-menu-bar__menu.ck-menu-bar__menu_top-level>.ck-menu-bar__menu__button{padding:var(--ck-spacing-small) var(--ck-spacing-medium);min-height:unset}.ck.ck-menu-bar__menu.ck-menu-bar__menu_top-level>.ck-menu-bar__menu__button .ck-button__label{width:unset;line-height:unset;overflow:visible}.ck.ck-menu-bar__menu.ck-menu-bar__menu_top-level>.ck-menu-bar__menu__button.ck-on{border-bottom-right-radius:0;border-bottom-left-radius:0}.ck.ck-menu-bar__menu.ck-menu-bar__menu_top-level>.ck-menu-bar__menu__button .ck-icon{display:none}.ck.ck-menu-bar__menu>.ck-menu-bar__menu__button>.ck-menu-bar__menu__button__arrow{pointer-events:none;z-index:var(--ck-z-default)}.ck.ck-menu-bar__menu:not(.ck-menu-bar__menu_top-level) .ck-menu-bar__menu__button{border-radius:0}.ck.ck-menu-bar__menu:not(.ck-menu-bar__menu_top-level) .ck-menu-bar__menu__button>.ck-menu-bar__menu__button__arrow{width:var(--ck-dropdown-arrow-size)}[dir="ltr"] :is(.ck.ck-menu-bar__menu:not(.ck-menu-bar__menu_top-level) .ck-menu-bar__menu__button>.ck-menu-bar__menu__button__arrow){margin-left:var(--ck-spacing-standard);margin-right:calc(-1 * var(--ck-spacing-small));transform:rotate(-90deg)}[dir="rtl"] :is(.ck.ck-menu-bar__menu:not(.ck-menu-bar__menu_top-level) .ck-menu-bar__menu__button>.ck-menu-bar__menu__button__arrow){left:var(--ck-spacing-standard);margin-right:var(--ck-spacing-small);margin-left:calc(-1 * var(--ck-spacing-small));transform:rotate(90deg)}.ck.ck-menu-bar__menu:not(.ck-menu-bar__menu_top-level) .ck-menu-bar__menu__button.ck-disabled>.ck-menu-bar__menu__button__arrow{opacity:var(--ck-disabled-opacity)}:root{--ck-menu-bar-menu-max-width: 75vw;--ck-menu-bar-nested-menu-horizontal-offset: 5px}.ck.ck-menu-bar__menu>.ck.ck-menu-bar__menu__panel{border-radius:var(--ck-rounded-corners-radius);box-shadow:var(--ck-drop-shadow), 0 0;background:var(--ck-color-dropdown-panel-background);border:1px solid var(--ck-color-dropdown-panel-border);height:fit-content;z-index:var(--ck-z-panel);max-width:var(--ck-menu-bar-menu-max-width);position:absolute;bottom:0}.ck.ck-menu-bar__menu>.ck.ck-menu-bar__menu__panel.ck-menu-bar__menu__panel_position_es,.ck.ck-menu-bar__menu>.ck.ck-menu-bar__menu__panel.ck-menu-bar__menu__panel_position_se{border-top-left-radius:0}.ck.ck-menu-bar__menu>.ck.ck-menu-bar__menu__panel.ck-menu-bar__menu__panel_position_ws,.ck.ck-menu-bar__menu>.ck.ck-menu-bar__menu__panel.ck-menu-bar__menu__panel_position_sw{border-top-right-radius:0}.ck.ck-menu-bar__menu>.ck.ck-menu-bar__menu__panel.ck-menu-bar__menu__panel_position_en,.ck.ck-menu-bar__menu>.ck.ck-menu-bar__menu__panel.ck-menu-bar__menu__panel_position_ne{border-bottom-left-radius:0}.ck.ck-menu-bar__menu>.ck.ck-menu-bar__menu__panel.ck-menu-bar__menu__panel_position_wn,.ck.ck-menu-bar__menu>.ck.ck-menu-bar__menu__panel.ck-menu-bar__menu__panel_position_nw{border-bottom-right-radius:0}.ck.ck-menu-bar__menu>.ck.ck-menu-bar__menu__panel:focus{outline:none}.ck.ck-menu-bar__menu>.ck.ck-menu-bar__menu__panel.ck-menu-bar__menu__panel_position_ne,.ck.ck-menu-bar__menu>.ck.ck-menu-bar__menu__panel.ck-menu-bar__menu__panel_position_nw{bottom:100%}.ck.ck-menu-bar__menu>.ck.ck-menu-bar__menu__panel.ck-menu-bar__menu__panel_position_se,.ck.ck-menu-bar__menu>.ck.ck-menu-bar__menu__panel.ck-menu-bar__menu__panel_position_sw{top:100%;bottom:auto}.ck.ck-menu-bar__menu>.ck.ck-menu-bar__menu__panel.ck-menu-bar__menu__panel_position_ne,.ck.ck-menu-bar__menu>.ck.ck-menu-bar__menu__panel.ck-menu-bar__menu__panel_position_se{left:0}.ck.ck-menu-bar__menu>.ck.ck-menu-bar__menu__panel.ck-menu-bar__menu__panel_position_nw,.ck.ck-menu-bar__menu>.ck.ck-menu-bar__menu__panel.ck-menu-bar__menu__panel_position_sw{right:0}.ck.ck-menu-bar__menu>.ck.ck-menu-bar__menu__panel.ck-menu-bar__menu__panel_position_es,.ck.ck-menu-bar__menu>.ck.ck-menu-bar__menu__panel.ck-menu-bar__menu__panel_position_en{left:calc(100% - var(--ck-menu-bar-nested-menu-horizontal-offset))}.ck.ck-menu-bar__menu>.ck.ck-menu-bar__menu__panel.ck-menu-bar__menu__panel_position_es{top:0}.ck.ck-menu-bar__menu>.ck.ck-menu-bar__menu__panel.ck-menu-bar__menu__panel_position_en{bottom:0}.ck.ck-menu-bar__menu>.ck.ck-menu-bar__menu__panel.ck-menu-bar__menu__panel_position_ws,.ck.ck-menu-bar__menu>.ck.ck-menu-bar__menu__panel.ck-menu-bar__menu__panel_position_wn{right:calc(100% - var(--ck-menu-bar-nested-menu-horizontal-offset))}.ck.ck-menu-bar__menu>.ck.ck-menu-bar__menu__panel.ck-menu-bar__menu__panel_position_ws{top:0}.ck.ck-menu-bar__menu>.ck.ck-menu-bar__menu__panel.ck-menu-bar__menu__panel_position_wn{bottom:0}.ck.ck-menu-bar .ck-list-item-button:focus,.ck.ck-menu-bar .ck-list-item-button:active{box-shadow:none;border-color:#0000}.ck.ck-menu-bar.ck-menu-bar_focus-border-enabled .ck-list-item-button:focus,.ck.ck-menu-bar.ck-menu-bar_focus-border-enabled .ck-list-item-button:active{z-index:2;border:var(--ck-focus-ring);box-shadow:var(--ck-focus-outer-shadow), 0 0;outline:none;position:relative}.ck.ck-menu-bar__menu{font-size:inherit;display:block}.ck.ck-menu-bar__menu.ck-menu-bar__menu_top-level{max-width:100%}.ck.ck-menu-bar__menu{position:relative}:root{--ck-menu-bar-menu-item-min-width: 18em}.ck.ck-menu-bar__menu .ck.ck-menu-bar__menu__item{min-width:var(--ck-menu-bar-menu-item-min-width)}.ck.ck-menu-bar__menu .ck-button.ck-menu-bar__menu__item__button{border-radius:0}.ck.ck-menu-bar__menu .ck-button.ck-menu-bar__menu__item__button>.ck-spinner-container,.ck.ck-menu-bar__menu .ck-button.ck-menu-bar__menu__item__button>.ck-spinner-container .ck-spinner{--ck-toolbar-spinner-size: 20px}.ck.ck-menu-bar__menu .ck-button.ck-menu-bar__menu__item__button>.ck-spinner-container{font-size:var(--ck-icon-font-size)}[dir="ltr"] :is(.ck.ck-menu-bar__menu .ck-button.ck-menu-bar__menu__item__button>.ck-spinner-container){margin-right:var(--ck-spacing-medium)}[dir="rtl"] :is(.ck.ck-menu-bar__menu .ck-button.ck-menu-bar__menu__item__button>.ck-spinner-container){margin-left:var(--ck-spacing-medium)}.ck-content code,.ibo-is-html-content code{background-color:#c7c7c74d;border-radius:2px;padding:0.15em}.ck.ck-editor__editable .ck-code_selected{background-color:#c7c7c780}.ck-content blockquote,.ibo-is-html-content blockquote{border-left:5px solid #ccc;margin-left:0;margin-right:0;padding-left:1.5em;padding-right:1.5em;font-style:italic;overflow:hidden}.ck-content[dir="rtl"] blockquote,.ibo-is-html-content[dir="rtl"] blockquote{border-left:0;border-right:5px solid #ccc}:root{--ck-bookmark-icon-hover-fill-color: var(--ck-color-widget-hover-border);--ck-bookmark-icon-selected-fill-color: var(--ck-color-focus-border);--ck-bookmark-icon-animation-duration: var(--ck-widget-handler-animation-duration);--ck-bookmark-icon-animation-curve: var(--ck-widget-handler-animation-curve)}.ck .ck-bookmark.ck-widget{outline:none;display:inline-block}.ck .ck-bookmark.ck-widget .ck-bookmark__icon .ck-icon__fill{transition:fill var(--ck-bookmark-icon-animation-duration) var(--ck-bookmark-icon-animation-curve)}.ck .ck-bookmark.ck-widget:hover .ck-bookmark__icon .ck-icon__fill{fill:var(--ck-bookmark-icon-hover-fill-color)}.ck .ck-bookmark.ck-widget.ck-widget_selected .ck-bookmark__icon .ck-icon__fill{fill:var(--ck-bookmark-icon-selected-fill-color)}.ck .ck-bookmark.ck-widget.ck-widget_selected,.ck .ck-bookmark.ck-widget.ck-widget_selected:hover{outline:none}.ck .ck-bookmark.ck-widget .ck-bookmark__icon{display:block;position:relative;top:-0.1em}.ck .ck-bookmark.ck-widget .ck-bookmark__icon .ck-icon{vertical-align:middle;width:auto;height:1.2em}.ck .ck-fake-bookmark-selection{background:var(--ck-color-link-fake-selection)}.ck .ck-fake-bookmark-selection_collapsed{border-right:1px solid var(--ck-color-base-text);outline:1px solid #ffffff80;height:100%;margin-right:-1px}.ck.ck-bookmark-balloon .ck.ck-toolbar>.ck-toolbar__items{flex-wrap:nowrap}.ck.ck-bookmark-toolbar__preview{padding:0 var(--ck-spacing-medium);max-width:var(--ck-input-width);text-overflow:ellipsis;text-align:center;-webkit-user-select:none;user-select:none;cursor:default;min-width:3em;font-weight:normal;overflow:hidden}:root{--ck-bookmark-form-width: 340px}@media screen and (width <= 600px){:root{--ck-bookmark-form-width: 300px}}.ck.ck-bookmark-form{width:var(--ck-bookmark-form-width)}:root{--ck-image-processing-highlight-color: #f9fafa;--ck-image-processing-background-color: #e3e5e8}.ck.ck-editor__editable .image.image-processing{position:relative}.ck.ck-editor__editable .image.image-processing:before{content:"";z-index:1;background:linear-gradient(90deg, var(--ck-image-processing-background-color), var(--ck-image-processing-highlight-color), var(--ck-image-processing-background-color));background-size:200% 100%;width:100%;height:100%;animation:2s linear infinite ck-image-processing-animation;position:absolute;top:0;left:0}.ck.ck-editor__editable .image.image-processing img{height:100%}@keyframes ck-image-processing-animation{0%{background-position:200% 0}100%{background-position:-200% 0}}:root{--ck-clipboard-drop-target-dot-width: 12px;--ck-clipboard-drop-target-dot-height: 8px;--ck-clipboard-drop-target-color: var(--ck-color-focus-border)}.ck.ck-editor__editable .ck.ck-clipboard-drop-target-position span{bottom:calc(-.5 * var(--ck-clipboard-drop-target-dot-height));top:calc(-.5 * var(--ck-clipboard-drop-target-dot-height));border:1px solid var(--ck-clipboard-drop-target-color);background:var(--ck-clipboard-drop-target-color);margin-left:-1px;position:absolute}.ck.ck-editor__editable .ck.ck-clipboard-drop-target-position span:after{content:"";width:0;height:0;left:50%;top:calc(-.5 * var(--ck-clipboard-drop-target-dot-height));border-color:var(--ck-clipboard-drop-target-color) transparent transparent transparent;border-width:calc(var(--ck-clipboard-drop-target-dot-height)) calc(.5 * var(--ck-clipboard-drop-target-dot-width)) 0 calc(.5 * var(--ck-clipboard-drop-target-dot-width));border-style:solid;display:block;position:absolute;transform:translateX(-50%)}.ck.ck-editor__editable .ck.ck-clipboard-drop-target-position span{width:0}.ck.ck-editor__editable .ck.ck-clipboard-drop-target-position{pointer-events:none;display:inline;position:relative}.ck.ck-editor__editable .ck-widget.ck-clipboard-drop-target-range{outline:var(--ck-widget-outline-thickness) solid var(--ck-clipboard-drop-target-color) !important}.ck.ck-editor__editable .ck-widget:-webkit-drag{zoom:0.6;outline:none !important}.ck.ck-editor__editable .ck-widget:-webkit-drag>.ck-widget__selection-handle,.ck.ck-editor__editable .ck-widget:-webkit-drag>.ck-widget__type-around{display:none}.ck.ck-clipboard-drop-target-line{border:1px solid var(--ck-clipboard-drop-target-color);background:var(--ck-clipboard-drop-target-color);height:0;z-index:var(--ck-z-default);margin-top:-1px;position:absolute}.ck.ck-clipboard-drop-target-line:before{content:"";top:calc(-.5 * var(--ck-clipboard-drop-target-dot-width));border-style:solid;width:0;height:0;position:absolute}.ck.ck-clipboard-drop-target-line{pointer-events:none}[dir="ltr"] .ck.ck-clipboard-drop-target-line:before{border-width:calc(.5 * var(--ck-clipboard-drop-target-dot-width)) 0 calc(.5 * var(--ck-clipboard-drop-target-dot-width)) var(--ck-clipboard-drop-target-dot-height);border-color:transparent transparent transparent var(--ck-clipboard-drop-target-color);left:-1px}[dir="rtl"] .ck.ck-clipboard-drop-target-line:before{border-width:calc(.5 * var(--ck-clipboard-drop-target-dot-width)) var(--ck-clipboard-drop-target-dot-height) calc(.5 * var(--ck-clipboard-drop-target-dot-width)) 0;border-color:transparent var(--ck-clipboard-drop-target-color) transparent transparent;right:-1px}:root{--ck-color-code-block-label-background: #757575}.ck.ck-editor__editable pre[data-language]:after{content:attr(data-language);background:var(--ck-color-code-block-label-background);font-size:10px;font-family:var(--ck-font-face);padding:var(--ck-spacing-tiny) var(--ck-spacing-medium);color:#fff;white-space:nowrap;line-height:16px;position:absolute;top:-1px;right:10px}.ck.ck-code-block-dropdown .ck-dropdown__panel{max-height:250px;overflow:hidden auto}.ck-content pre,.ibo-is-html-content pre{color:#353535;text-align:left;tab-size:4;white-space:pre-wrap;direction:ltr;background:#c7c7c74d;border:1px solid #c4c4c4;border-radius:2px;min-width:200px;margin:0.9em 0;padding:1em;font-style:normal}.ck-content pre code,.ibo-is-html-content pre code{background:unset;border-radius:0;padding:0}.ck.ck-editor__editable pre{position:relative}:root{--ck-content-font-family: Helvetica, Arial, Tahoma, Verdana, Sans-Serif;--ck-content-font-size: medium;--ck-content-font-color: #000;--ck-content-line-height: 1.5;--ck-content-word-break: normal;--ck-content-overflow-wrap: break-word}.ck-content,.ibo-is-html-content{font-family:var(--ck-content-font-family);font-size:var(--ck-content-font-size);color:var(--ck-content-font-color);line-height:var(--ck-content-line-height);word-break:var(--ck-content-word-break);overflow-wrap:var(--ck-content-overflow-wrap)}.ck.ck-editor__main>.ck-editor__editable{background:var(--ck-color-base-background);border-radius:var(--ck-rounded-corners-radius);border-top-left-radius:0;border-top-right-radius:0}.ck.ck-editor__main>.ck-editor__editable:not(.ck-focused){border-color:var(--ck-color-base-border)}.ck.ck-editor{position:relative}.ck.ck-editor .ck-editor__top .ck-sticky-panel .ck-toolbar{z-index:var(--ck-z-panel)}.ck.ck-menu-bar{border:none;border-bottom:1px solid var(--ck-color-toolbar-border)}.ck.ck-emoji{width:320px}.ck .ck.ck-emoji__search{padding:var(--ck-spacing-large);padding-bottom:var(--ck-spacing-medium);justify-content:space-between;align-items:center;display:flex}.ck .ck.ck-emoji__search>.ck.ck-search{flex:1}.ck .ck-fake-emoji-selection{background:var(--ck-color-link-fake-selection)}.ck .ck-fake-emoji-selection_collapsed{border-right:1px solid var(--ck-color-base-text);outline:1px solid #ffffff80;height:100%;margin-right:-1px}div.ck.ck-balloon-panel.ck-emoji-picker-balloon{z-index:calc(var(--ck-z-dialog) + 1)}.ck.ck-emoji__categories-list{margin:0 var(--ck-spacing-large);justify-content:space-between;display:flex}.ck.ck-emoji__categories-list>.ck.ck-button.ck-button_with-text{font-size:var(--ck-font-size-big);min-width:var(--ck-font-size-big);min-height:var(--ck-font-size-big);border-width:0 0 2px;border-bottom-style:solid;border-bottom-color:#0000;padding:0}.ck.ck-emoji__categories-list>.ck.ck-button.ck-button_with-text.ck-emoji__category-item.ck-on{border-bottom-color:var(--ck-color-base-active)}.ck.ck-emoji__categories-list>.ck.ck-button.ck-button_with-text>span{margin:auto}:root{--ck-emoji-grid-tile-size: 27px}.ck.ck-emoji .ck.ck-emoji__tiles{border-top:1px solid var(--ck-color-base-border);max-width:100%;max-height:min(265px, 40vh);overflow:hidden auto}.ck.ck-emoji .ck.ck-emoji__tiles .ck-emoji__grid{grid-template-columns:repeat(auto-fill, minmax(var(--ck-emoji-grid-tile-size), 1fr));margin:var(--ck-spacing-standard) var(--ck-spacing-large);grid-gap:var(--ck-spacing-small);display:grid}.ck.ck-emoji .ck.ck-emoji__tiles .ck-emoji__tile{width:var(--ck-emoji-grid-tile-size);height:var(--ck-emoji-grid-tile-size);min-width:var(--ck-emoji-grid-tile-size);min-height:var(--ck-emoji-grid-tile-size);border:0;padding:0;font-size:1.5em;transition:box-shadow 0.2s}@media (prefers-reduced-motion:reduce){.ck.ck-emoji .ck.ck-emoji__tiles .ck-emoji__tile{transition:none}}.ck.ck-emoji .ck.ck-emoji__tiles .ck-emoji__tile:focus:not(.ck-disabled),.ck.ck-emoji .ck.ck-emoji__tiles .ck-emoji__tile:hover:not(.ck-disabled){box-shadow:inset 0 0 0 1px var(--ck-color-base-background), 0 0 0 2px var(--ck-color-focus-border);border:0}.ck.ck-emoji .ck.ck-emoji__tiles .ck-emoji__tile .ck-button__label{line-height:var(--ck-emoji-grid-tile-size);text-align:center;width:100%}.ck.ck-form.ck-emoji-picker-form{padding-bottom:0}.ck.ck-form.ck-emoji-picker-form .ck.ck-dropdown .ck-dropdown__button:not(:focus){border-color:#0000}.ck.ck-emoji__skin-tone{margin-left:var(--ck-spacing-standard)}.ck.ck-emoji__skin-tone>.ck.ck-dropdown .ck.ck-list__item{min-width:1em}.ck.ck-emoji__skin-tone>.ck.ck-dropdown .ck-button.ck-dropdown__button .ck-button__label{width:initial}.ck.ck-placeholder,.ck .ck-placeholder{position:relative}@media (forced-colors:active){.ck.ck-placeholder,.ck .ck-placeholder{forced-color-adjust:preserve-parent-color}}:is(.ck.ck-placeholder, .ck .ck-placeholder):before{content:attr(data-placeholder);cursor:text;pointer-events:none;position:absolute;left:0;right:0}@media (forced-colors:none){:is(.ck.ck-placeholder, .ck .ck-placeholder):before{color:var(--ck-color-engine-placeholder-text)}}@media (forced-colors:active){:is(.ck.ck-placeholder, .ck .ck-placeholder):before{margin-left:1px;font-style:italic}}.ck.ck-read-only .ck-placeholder:before{display:none}.ck.ck-reset_all .ck-placeholder{position:relative}.ck.ck-editor__editable span[data-ck-unsafe-element]{display:none}.ck-find-result{background:var(--ck-color-highlight-background);color:var(--ck-color-text)}.ck-find-result_selected{background:#ff9633}.ck.ck-find-and-replace-form{width:400px;max-width:100%}.ck.ck-find-and-replace-form:focus{outline:none}.ck.ck-find-and-replace-form .ck-find-and-replace-form__inputs,.ck.ck-find-and-replace-form .ck-find-and-replace-form__actions{padding:var(--ck-spacing-large);flex-flow:wrap;flex:auto;align-content:stretch;align-items:center;margin:0;display:flex}:is(.ck.ck-find-and-replace-form .ck-find-and-replace-form__inputs, .ck.ck-find-and-replace-form .ck-find-and-replace-form__actions)>.ck-button{flex:none}[dir="ltr"] :is(.ck.ck-find-and-replace-form .ck-find-and-replace-form__inputs, .ck.ck-find-and-replace-form .ck-find-and-replace-form__actions)>*+*{margin-left:var(--ck-spacing-standard)}[dir="rtl"] :is(.ck.ck-find-and-replace-form .ck-find-and-replace-form__inputs, .ck.ck-find-and-replace-form .ck-find-and-replace-form__actions)>*+*{margin-right:var(--ck-spacing-standard)}:is(.ck.ck-find-and-replace-form .ck-find-and-replace-form__inputs, .ck.ck-find-and-replace-form .ck-find-and-replace-form__actions) .ck-labeled-field-view{flex:auto}:is(.ck.ck-find-and-replace-form .ck-find-and-replace-form__inputs, .ck.ck-find-and-replace-form .ck-find-and-replace-form__actions) .ck-labeled-field-view .ck-input{width:100%;min-width:50px}.ck.ck-find-and-replace-form .ck-find-and-replace-form__inputs{align-items:flex-start}.ck.ck-find-and-replace-form .ck-find-and-replace-form__inputs>.ck-button-prev>.ck-icon{transform:rotate(90deg)}.ck.ck-find-and-replace-form .ck-find-and-replace-form__inputs>.ck-button-next>.ck-icon{transform:rotate(-90deg)}.ck.ck-find-and-replace-form .ck-find-and-replace-form__inputs .ck-results-counter{color:var(--ck-color-base-border);position:absolute;top:50%;transform:translateY(-50%)}[dir="ltr"] :is(.ck.ck-find-and-replace-form .ck-find-and-replace-form__inputs .ck-results-counter){right:var(--ck-spacing-standard)}[dir="rtl"] :is(.ck.ck-find-and-replace-form .ck-find-and-replace-form__inputs .ck-results-counter){left:var(--ck-spacing-standard)}.ck.ck-find-and-replace-form .ck-find-and-replace-form__inputs>.ck-labeled-field-replace{padding-top:var(--ck-spacing-standard);flex:0 0 100%}[dir="ltr"] :is(.ck.ck-find-and-replace-form .ck-find-and-replace-form__inputs>.ck-labeled-field-replace){margin-left:0}[dir="rtl"] :is(.ck.ck-find-and-replace-form .ck-find-and-replace-form__inputs>.ck-labeled-field-replace){margin-right:0}.ck.ck-find-and-replace-form .ck-find-and-replace-form__actions{margin-top:calc(-1 * var(--ck-spacing-large));flex-wrap:wrap;justify-content:flex-end}.ck.ck-find-and-replace-form .ck-find-and-replace-form__actions>.ck-button-find{font-weight:bold}.ck.ck-find-and-replace-form .ck-find-and-replace-form__actions>.ck-button-find .ck-button__label{padding-left:var(--ck-spacing-large);padding-right:var(--ck-spacing-large)}.ck.ck-find-and-replace-form .ck-switchbutton{flex-flow:row;justify-content:space-between;align-items:center;width:100%;display:flex}@media screen and (width <= 600px){.ck.ck-find-and-replace-form{width:300px;max-width:100%}.ck.ck-find-and-replace-form.ck-find-and-replace-form__input{flex-wrap:wrap}.ck.ck-find-and-replace-form.ck-find-and-replace-form__input .ck-labeled-field-view{width:100%;margin-bottom:var(--ck-spacing-standard);flex:1 0 auto}.ck.ck-find-and-replace-form.ck-find-and-replace-form__input>.ck-button{text-align:center}.ck.ck-find-and-replace-form.ck-find-and-replace-form__input>.ck-button:first-of-type{flex:auto}[dir="ltr"] .ck.ck-find-and-replace-form.ck-find-and-replace-form__input>.ck-button:first-of-type{margin-left:0}[dir="rtl"] .ck.ck-find-and-replace-form.ck-find-and-replace-form__input>.ck-button:first-of-type{margin-right:0}.ck.ck-find-and-replace-form.ck-find-and-replace-form__input>.ck-button:first-of-type .ck-button__label{text-align:center;width:100%}.ck.ck-find-and-replace-form.ck-find-and-replace-form__actions>:not(.ck-labeled-field-view){flex-wrap:wrap;flex:auto}.ck.ck-find-and-replace-form.ck-find-and-replace-form__actions>:not(.ck-labeled-field-view)>.ck-button{text-align:center}.ck.ck-find-and-replace-form.ck-find-and-replace-form__actions>:not(.ck-labeled-field-view)>.ck-button:first-of-type{flex:auto}[dir="ltr"] .ck.ck-find-and-replace-form.ck-find-and-replace-form__actions>:not(.ck-labeled-field-view)>.ck-button:first-of-type{margin-left:0}[dir="rtl"] .ck.ck-find-and-replace-form.ck-find-and-replace-form__actions>:not(.ck-labeled-field-view)>.ck-button:first-of-type{margin-right:0}.ck.ck-find-and-replace-form.ck-find-and-replace-form__actions>:not(.ck-labeled-field-view)>.ck-button .ck-button__label{text-align:center;width:100%}}:root{--ck-content-font-size-tiny: .7em;--ck-content-font-size-small: .85em;--ck-content-font-size-big: 1.4em;--ck-content-font-size-huge: 1.8em}.ck-content .text-tiny,.ibo-is-html-content .text-tiny{font-size:var(--ck-content-font-size-tiny)}.ck-content .text-small,.ibo-is-html-content .text-small{font-size:var(--ck-content-font-size-small)}.ck-content .text-big,.ibo-is-html-content .text-big{font-size:var(--ck-content-font-size-big)}.ck-content .text-huge,.ibo-is-html-content .text-huge{font-size:var(--ck-content-font-size-huge)}html.ck-fullscreen,body.ck-fullscreen{--ck-z-fullscreen: 10000;--ck-z-default: calc(var(--ck-z-fullscreen) + 1);--ck-z-panel: calc(var(--ck-z-default) + 999);--ck-z-dialog: 100000;overflow:hidden}:is(html.ck-fullscreen, body.ck-fullscreen) .ckbox:not(#n){--ckbox-z-index-root: calc(var(--ck-z-dialog) + 1);position:absolute}:is(html.ck-fullscreen, body.ck-fullscreen) .ckbox:not(#n) .ckbox-img-editor{--ckbox-z-index-preview: calc(var(--ck-z-dialog) + 1)}:is(html.ck-fullscreen, body.ck-fullscreen) .ck-pagination-view-line{z-index:calc(var(--ck-z-fullscreen) + 1)}:is(html.ck-fullscreen, body.ck-fullscreen) .page-break__label{z-index:calc(var(--ck-z-fullscreen) + 2)}.ck.ck-fullscreen__main-wrapper{width:100%;height:100%;z-index:var(--ck-z-fullscreen);background:var(--ck-color-base-foreground);flex-direction:column;display:flex;position:fixed;top:0;left:0}.ck.ck-fullscreen__main-wrapper .ck.ck-revision-history-ui__changes-navigation{margin-top:0;margin-bottom:0}:not(body>.ck-fullscreen__main-wrapper).ck-fullscreen__main-wrapper{position:absolute}:not(body>.ck-fullscreen__main-wrapper).ck-fullscreen__main-wrapper .ck-fullscreen__top-wrapper{border-top:1px solid var(--ck-color-base-border);border-left:1px solid var(--ck-color-base-border);border-right:1px solid var(--ck-color-base-border);border-radius:var(--ck-border-radius) 0}.ck-fullscreen__menu-bar .ck.ck-menu-bar{border:none}.ck.ck-fullscreen__toolbar .ck-toolbar{border-left:0;border-right:0;border-radius:0}.ck-fullscreen__main-wrapper .ck-fullscreen__editable-wrapper{--ck-fullscreen-editor-top-margin: 28px;--ck-fullscreen-editor-bottom-margin: 28px;justify-content:flex-start;max-height:100%;display:flex;overflow:auto}.ck-fullscreen__main-wrapper .ck-fullscreen__editable{margin-top:var(--ck-fullscreen-editor-top-margin);height:100%;margin-left:auto}.ck-fullscreen__main-wrapper .ck-fullscreen__editable:after{content:"";height:var(--ck-fullscreen-editor-bottom-margin);display:block}.ck-fullscreen__main-wrapper .ck-fullscreen__editable .ck.ck-editor__editable:not(.ck-editor__nested-editable){box-sizing:border-box;border:1px var(--ck-color-base-border) solid;background:#fff;width:795.701px;max-width:795.701px;height:fit-content;min-height:297mm;margin:0;padding:20mm 12mm;box-shadow:0 2px 3px #00000014}.ck-fullscreen__main-wrapper .ck-fullscreen__editable .ck-source-editing-area{width:795.701px}.ck-fullscreen__sidebar{width:270px;margin-top:var(--ck-fullscreen-editor-top-margin);margin-left:10px}.ck-fullscreen__left-sidebar{--ck-user-avatar-size: 28px;box-sizing:border-box;background-color:#0000;flex-direction:column;align-self:flex-start;height:100%;margin-top:0;margin-right:10px;font-family:Helvetica, Arial, sans-serif;display:flex;position:sticky;top:0}.ck-fullscreen__left-sidebar .ck-button.ck-fullscreen__left-sidebar-toggle-button{--ck-icon-size: 20px;--ck-ui-component-min-height: 0px;margin-top:var(--ck-fullscreen-editor-top-margin);margin-bottom:var(--ck-spacing-large);opacity:0.5;border-radius:100%;align-self:flex-start;padding-top:0}.ck-fullscreen__left-sidebar>.ck-fullscreen__left-sidebar-sticky{min-width:270px}.ck-fullscreen__left-sidebar>.ck-fullscreen__left-sidebar-sticky:first-child{padding-top:var(--ck-fullscreen-editor-top-margin)}.ck-fullscreen__left-sidebar.ck-fullscreen__left-sidebar--collapsed{width:65px}.ck-fullscreen__left-sidebar.ck-fullscreen__left-sidebar--collapsed>:not(.ck-fullscreen__left-sidebar-toggle-button){display:none}.ck-fullscreen__left-sidebar .ck.ck-presence-list--collapsed{--ck-user-avatar-size: 32px}.ck-fullscreen__left-sidebar .ck-user,.ck-fullscreen__left-sidebar .ck-presence-list__users-counter__text{font-size:0.85em}.ck-fullscreen__left-sidebar-item{padding:var(--ck-spacing-medium);margin-bottom:var(--ck-spacing-medium)}.ck-fullscreen__left-sidebar-item:first-child{padding-top:0}.ck-fullscreen__left-sidebar-item:last-child{margin-bottom:0}.ck-fullscreen__left-sidebar-header{--ck-fullscreen-presence-list-header-font-size: .875em;font-size:var(--ck-fullscreen-presence-list-header-font-size);color:var(--ck-document-outline-item-default-color);white-space:nowrap;text-overflow:ellipsis;font-weight:bold;overflow:hidden}.ck-fullscreen__left-sidebar--sticky{position:sticky;top:0}.ck-fullscreen__left-sidebar--sticky>:first-child{padding-top:0}.ck-fullscreen__presence-list{margin-top:var(--ck-spacing-medium)}.ck-fullscreen__left-sidebar-item--no-margin{margin:0}.ck-fullscreen__left-sidebar .ck.ck-document-outline{padding-top:0;padding-left:0;padding-right:0}.ck-fullscreen__document-outline-wrapper{padding-top:0;overflow-y:auto}.ck-fullscreen__sidebar.ck-fullscreen__right-sidebar{margin-top:var(--ck-fullscreen-editor-top-margin);margin-right:auto}.ck-fullscreen__sidebar.ck-fullscreen__right-sidebar:not(.ck-fullscreen__right-sidebar--collapsed)>:first-child{min-width:270px}.ck-fullscreen__sidebar.ck-fullscreen__right-sidebar.ck-fullscreen__right-sidebar--collapsed{width:65px}.ck-fullscreen__sidebar.ck-fullscreen__right-sidebar.ck-fullscreen__right-sidebar--collapsed>:first-child{min-width:65px}.ck.ck-fullscreen__right-edge{margin-top:0;margin-left:10px;position:sticky;top:0}.ck.ck-fullscreen__right-edge>:first-child{border-top:none;border-bottom:none;border-right:none;width:495px;height:100%}.ck.ck-heading_heading1 .ck-button__label{font-size:20px}.ck.ck-heading_heading2 .ck-button__label{font-size:17px}.ck.ck-heading_heading3 .ck-button__label{font-size:14px}.ck[class*="ck-heading_heading"]{font-weight:bold}.ck.ck-dropdown.ck-heading-dropdown .ck-dropdown__button .ck-button__label{width:8em}.ck.ck-dropdown.ck-heading-dropdown .ck-dropdown__panel .ck-list__item{min-width:18em}:root{--ck-content-highlight-marker-yellow: #fdfd77;--ck-content-highlight-marker-green: #62f962;--ck-content-highlight-marker-pink: #fc7899;--ck-content-highlight-marker-blue: #72ccfd;--ck-content-highlight-pen-red: #e71313;--ck-content-highlight-pen-green: #128a00}.ck-content .marker-yellow,.ibo-is-html-content .marker-yellow{background-color:var(--ck-content-highlight-marker-yellow)}.ck-content .marker-green,.ibo-is-html-content .marker-green{background-color:var(--ck-content-highlight-marker-green)}.ck-content .marker-pink,.ibo-is-html-content .marker-pink{background-color:var(--ck-content-highlight-marker-pink)}.ck-content .marker-blue,.ibo-is-html-content .marker-blue{background-color:var(--ck-content-highlight-marker-blue)}.ck-content .pen-red,.ibo-is-html-content .pen-red{color:var(--ck-content-highlight-pen-red);background-color:#0000}.ck-content .pen-green,.ibo-is-html-content .pen-green{color:var(--ck-content-highlight-pen-green);background-color:#0000}.ck-editor__editable .ck-horizontal-line{display:flow-root}.ck-content hr,.ibo-is-html-content hr{background:#dedede;border:0;height:4px;margin:15px 0}:root{--ck-html-embed-content-width: calc(100% - 1.5 * var(--ck-icon-size));--ck-html-embed-source-height: 10em;--ck-html-embed-unfocused-outline-width: 1px;--ck-html-embed-content-min-height: calc(var(--ck-icon-size) + var(--ck-spacing-standard));--ck-html-embed-source-disabled-background: var(--ck-color-base-foreground);--ck-html-embed-source-disabled-color: #737373}.ck-widget.raw-html-embed{font-size:var(--ck-font-size-base);background-color:var(--ck-color-base-foreground);min-width:15em;margin:0.9em auto;display:flow-root;position:relative}.ck-widget.raw-html-embed:not(.ck-widget_selected):not(:hover){outline:var(--ck-html-embed-unfocused-outline-width) dashed var(--ck-color-widget-blurred-border)}.ck-widget.raw-html-embed[dir="ltr"]{text-align:left}.ck-widget.raw-html-embed[dir="rtl"]{text-align:right}.ck-widget.raw-html-embed:before{content:attr(data-html-embed-label);top:calc(-1 * var(--ck-html-embed-unfocused-outline-width));left:var(--ck-spacing-standard);transition:background var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve);padding:calc(var(--ck-spacing-tiny) + var(--ck-html-embed-unfocused-outline-width)) var(--ck-spacing-small) var(--ck-spacing-tiny);border-radius:0 0 var(--ck-border-radius) var(--ck-border-radius);color:var(--ck-color-base-background);font-size:var(--ck-font-size-tiny);font-family:var(--ck-font-face);z-index:1;background:#999;position:absolute}.ck-widget.raw-html-embed[dir="rtl"]:before{left:auto;right:var(--ck-spacing-standard)}.ck-widget.raw-html-embed[dir="ltr"] .ck-widget__type-around .ck-widget__type-around__button.ck-widget__type-around__button_before{margin-left:50px}.ck.ck-editor__editable.ck-blurred .ck-widget.raw-html-embed.ck-widget_selected:before{padding:var(--ck-spacing-tiny) var(--ck-spacing-small);top:0}.ck.ck-editor__editable:not(.ck-blurred) .ck-widget.raw-html-embed.ck-widget_selected:before{padding:var(--ck-spacing-tiny) var(--ck-spacing-small);background:var(--ck-color-focus-border);top:0}.ck.ck-editor__editable .ck-widget.raw-html-embed:not(.ck-widget_selected):hover:before{padding:var(--ck-spacing-tiny) var(--ck-spacing-small);top:0}.ck-widget.raw-html-embed .raw-html-embed__content-wrapper{padding:var(--ck-spacing-standard)}.ck-widget.raw-html-embed .raw-html-embed__buttons-wrapper{top:var(--ck-spacing-standard);right:var(--ck-spacing-standard);display:flex;position:absolute}.ck-widget.raw-html-embed .raw-html-embed__buttons-wrapper .ck-button.raw-html-embed__save-button{color:var(--ck-color-button-save)}.ck-widget.raw-html-embed .raw-html-embed__buttons-wrapper .ck-button.raw-html-embed__cancel-button{color:var(--ck-color-button-cancel)}.ck-widget.raw-html-embed .raw-html-embed__buttons-wrapper .ck-button:not(:first-child){margin-top:var(--ck-spacing-small)}.ck-widget.raw-html-embed .raw-html-embed__buttons-wrapper{flex-direction:column}.ck-widget.raw-html-embed[dir="rtl"] .raw-html-embed__buttons-wrapper{left:var(--ck-spacing-standard);right:auto}.ck-widget.raw-html-embed .raw-html-embed__source{box-sizing:border-box;height:var(--ck-html-embed-source-height);width:var(--ck-html-embed-content-width);resize:none;min-width:0;padding:var(--ck-spacing-standard);tab-size:4;white-space:pre-wrap;font-family:monospace;font-size:var(--ck-font-size-base);text-align:left;direction:ltr}.ck-widget.raw-html-embed .raw-html-embed__source[disabled]{background:var(--ck-html-embed-source-disabled-background);color:var(--ck-html-embed-source-disabled-color);-webkit-text-fill-color:var(--ck-html-embed-source-disabled-color);opacity:1}.ck-widget.raw-html-embed .raw-html-embed__preview{min-height:var(--ck-html-embed-content-min-height);width:var(--ck-html-embed-content-width);position:relative;overflow:hidden}.ck-editor__editable:not(.ck-read-only) :is(.ck-widget.raw-html-embed .raw-html-embed__preview){pointer-events:none}.ck-widget.raw-html-embed .raw-html-embed__preview{display:flex}.ck-widget.raw-html-embed .raw-html-embed__preview-content{box-sizing:border-box;background-color:var(--ck-color-base-foreground);border-collapse:separate;width:100%;margin:auto;display:table;position:relative}.ck-widget.raw-html-embed .raw-html-embed__preview-content>*{margin-left:auto;margin-right:auto}.ck-widget.raw-html-embed .raw-html-embed__preview-content{border-spacing:7px}.ck-widget.raw-html-embed .raw-html-embed__preview-placeholder{color:var(--ck-html-embed-source-disabled-color);justify-content:center;align-items:center;display:flex;position:absolute;inset:0}.ck-widget.raw-html-embed{font-style:normal}:root{--ck-html-object-embed-unfocused-outline-width: 1px}.ck-widget.html-object-embed{font-size:var(--ck-font-size-base);background-color:var(--ck-color-base-foreground);padding:var(--ck-spacing-small);padding-top:calc(var(--ck-font-size-tiny) + var(--ck-spacing-large));min-width:calc(76px + var(--ck-spacing-standard))}.ck-widget.html-object-embed:not(.ck-widget_selected):not(:hover){outline:var(--ck-html-object-embed-unfocused-outline-width) dashed var(--ck-color-widget-blurred-border)}.ck-widget.html-object-embed:before{content:attr(data-html-object-embed-label);top:0;left:var(--ck-spacing-standard);transition:background var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve);padding:calc(var(--ck-spacing-tiny) + var(--ck-html-object-embed-unfocused-outline-width)) var(--ck-spacing-small) var(--ck-spacing-tiny);border-radius:0 0 var(--ck-border-radius) var(--ck-border-radius);color:var(--ck-color-base-background);font-style:normal;font-weight:normal;font-size:var(--ck-font-size-tiny);font-family:var(--ck-font-face);background:#999;position:absolute}.ck-widget.html-object-embed .ck-widget__type-around .ck-widget__type-around__button.ck-widget__type-around__button_before{margin-left:50px}.ck-widget.html-object-embed .html-object-embed__content{pointer-events:none}div.ck-widget.html-object-embed{margin:1em auto}span.ck-widget.html-object-embed{display:inline-block}:root{--ck-content-color-image-caption-background: #f7f7f7;--ck-content-color-image-caption-text: #333;--ck-color-image-caption-highlighted-background: #fd0}.ck-content .image>figcaption,.ibo-is-html-content .image>figcaption{caption-side:bottom;word-break:normal;overflow-wrap:anywhere;break-before:avoid;color:var(--ck-content-color-image-caption-text);background-color:var(--ck-content-color-image-caption-background);outline-offset:-1px;padding:0.6em;font-size:0.75em;display:table-caption}@media (forced-colors:active){.ck-content .image>figcaption,.ibo-is-html-content .image>figcaption{background-color:unset;color:unset}}@media (forced-colors:none){.ck.ck-editor__editable .image>figcaption.image__caption_highlighted{animation:0.6s ease-out ck-image-caption-highlight}}@media (prefers-reduced-motion:reduce){.ck.ck-editor__editable .image>figcaption.image__caption_highlighted{animation:none}}@keyframes ck-image-caption-highlight{0%{background-color:var(--ck-color-image-caption-highlighted-background)}100%{background-color:var(--ck-content-color-image-caption-background)}}.ck-content img.image_resized,.ibo-is-html-content img.image_resized{height:auto}.ck-content .image.image_resized,.ibo-is-html-content .image.image_resized{box-sizing:border-box;max-width:100%;display:block}.ck-content .image.image_resized img,.ibo-is-html-content .image.image_resized img{width:100%}.ck-content .image.image_resized>figcaption,.ibo-is-html-content .image.image_resized>figcaption{display:block}:is(.ck.ck-editor__editable td, .ck.ck-editor__editable th) .image-inline.image_resized img{max-width:100%}[dir="ltr"] .ck.ck-button.ck-button_with-text.ck-resize-image-button .ck-button__icon{margin-right:var(--ck-spacing-standard)}[dir="rtl"] .ck.ck-button.ck-button_with-text.ck-resize-image-button .ck-button__icon{margin-left:var(--ck-spacing-standard)}.ck.ck-dropdown .ck-button.ck-resize-image-button .ck-button__label{width:4em}:root{--ck-content-image-style-spacing: 1.5em;--ck-content-inline-image-style-spacing: calc(var(--ck-content-image-style-spacing) / 2)}.ck-content .image.image-style-block-align-left,.ibo-is-html-content .image.image-style-block-align-left,.ck-content .image.image-style-block-align-right,.ibo-is-html-content .image.image-style-block-align-right{max-width:calc(100% - var(--ck-content-image-style-spacing))}.ck-content .image.image-style-align-left,.ibo-is-html-content .image.image-style-align-left,.ck-content .image.image-style-align-right,.ibo-is-html-content .image.image-style-align-right{clear:none}.ck-content .image.image-style-side,.ibo-is-html-content .image.image-style-side{float:right;margin-left:var(--ck-content-image-style-spacing);max-width:50%}.ck-content .image.image-style-align-left,.ibo-is-html-content .image.image-style-align-left{float:left;margin-right:var(--ck-content-image-style-spacing)}.ck-content .image.image-style-align-right,.ibo-is-html-content .image.image-style-align-right{float:right;margin-left:var(--ck-content-image-style-spacing)}.ck-content .image.image-style-block-align-right,.ibo-is-html-content .image.image-style-block-align-right{margin-left:auto;margin-right:0}.ck-content .image.image-style-block-align-left,.ibo-is-html-content .image.image-style-block-align-left{margin-left:0;margin-right:auto}.ck-content .image-style-align-center,.ibo-is-html-content .image-style-align-center{margin-left:auto;margin-right:auto}.ck-content .image-style-align-left,.ibo-is-html-content .image-style-align-left{float:left;margin-right:var(--ck-content-image-style-spacing)}.ck-content .image-style-align-right,.ibo-is-html-content .image-style-align-right{float:right;margin-left:var(--ck-content-image-style-spacing)}.ck-content p+.image.image-style-align-left,.ibo-is-html-content p+.image.image-style-align-left,.ck-content p+.image.image-style-align-right,.ibo-is-html-content p+.image.image-style-align-right,.ck-content p+.image.image-style-side,.ibo-is-html-content p+.image.image-style-side{margin-top:0}.ck-content .image-inline.image-style-align-left,.ibo-is-html-content .image-inline.image-style-align-left,.ck-content .image-inline.image-style-align-right,.ibo-is-html-content .image-inline.image-style-align-right{margin-top:var(--ck-content-inline-image-style-spacing);margin-bottom:var(--ck-content-inline-image-style-spacing)}.ck-content .image-inline.image-style-align-left,.ibo-is-html-content .image-inline.image-style-align-left{margin-right:var(--ck-content-inline-image-style-spacing)}.ck-content .image-inline.image-style-align-right,.ibo-is-html-content .image-inline.image-style-align-right{margin-left:var(--ck-content-inline-image-style-spacing)}:is(.ck.ck-splitbutton.ck-splitbutton_flatten:hover, .ck.ck-splitbutton.ck-splitbutton_flatten.ck-splitbutton_open)>.ck-splitbutton__action:not(.ck-disabled),:is(.ck.ck-splitbutton.ck-splitbutton_flatten:hover, .ck.ck-splitbutton.ck-splitbutton_flatten.ck-splitbutton_open)>.ck-splitbutton__arrow:not(.ck-disabled),:is(.ck.ck-splitbutton.ck-splitbutton_flatten:hover, .ck.ck-splitbutton.ck-splitbutton_flatten.ck-splitbutton_open)>.ck-splitbutton__arrow:not(.ck-disabled):not(:hover){background-color:var(--ck-color-button-on-background)}:is(:is(.ck.ck-splitbutton.ck-splitbutton_flatten:hover, .ck.ck-splitbutton.ck-splitbutton_flatten.ck-splitbutton_open)>.ck-splitbutton__action:not(.ck-disabled), :is(.ck.ck-splitbutton.ck-splitbutton_flatten:hover, .ck.ck-splitbutton.ck-splitbutton_flatten.ck-splitbutton_open)>.ck-splitbutton__arrow:not(.ck-disabled), :is(.ck.ck-splitbutton.ck-splitbutton_flatten:hover, .ck.ck-splitbutton.ck-splitbutton_flatten.ck-splitbutton_open)>.ck-splitbutton__arrow:not(.ck-disabled):not(:hover)):after{display:none}.ck.ck-splitbutton.ck-splitbutton_flatten.ck-splitbutton_open:hover>.ck-splitbutton__action:not(.ck-disabled),.ck.ck-splitbutton.ck-splitbutton_flatten.ck-splitbutton_open:hover>.ck-splitbutton__arrow:not(.ck-disabled),.ck.ck-splitbutton.ck-splitbutton_flatten.ck-splitbutton_open:hover>.ck-splitbutton__arrow:not(.ck-disabled):not(:hover){background-color:var(--ck-color-button-on-hover-background)}:is(.ck.ck-editor__editable .image, .ck.ck-editor__editable .image-inline).ck-appear{animation:0.7s fadeIn}@media (prefers-reduced-motion:reduce){:is(.ck.ck-editor__editable .image, .ck.ck-editor__editable .image-inline).ck-appear{opacity:1;animation:none}}.ck.ck-editor__editable .image,.ck.ck-editor__editable .image-inline{position:relative}.ck.ck-editor__editable .image .ck-progress-bar,.ck.ck-editor__editable .image-inline .ck-progress-bar{background:var(--ck-color-upload-bar-background);width:0;height:2px;transition:width 0.1s;position:absolute;top:0;left:0}@keyframes fadeIn{from{opacity:0}to{opacity:1}}:root{--ck-color-image-upload-icon: #fff;--ck-color-image-upload-icon-background: #008a00;--ck-image-upload-icon-size: 20;--ck-image-upload-icon-width: 2px;--ck-image-upload-icon-is-visible: clamp(0px, 100% - 50px, 1px)}.ck-image-upload-complete-icon{opacity:0;background:var(--ck-color-image-upload-icon-background);font-size:calc(1px * var(--ck-image-upload-icon-size));width:calc(var(--ck-image-upload-icon-is-visible) * var(--ck-image-upload-icon-size));height:calc(var(--ck-image-upload-icon-is-visible) * var(--ck-image-upload-icon-size));top:min(var(--ck-spacing-medium), 6%);right:min(var(--ck-spacing-medium), 6%);border-radius:50%;animation-name:ck-upload-complete-icon-show, ck-upload-complete-icon-hide;animation-duration:0.5s, 0.5s;animation-delay:0s, 3s;animation-fill-mode:forwards, forwards;display:block;position:absolute;overflow:hidden}.ck-image-upload-complete-icon:after{opacity:0;transform-origin:0 0;border-top:var(--ck-image-upload-icon-width) solid var(--ck-color-image-upload-icon);border-right:var(--ck-image-upload-icon-width) solid var(--ck-color-image-upload-icon);box-sizing:border-box;content:"";width:0;height:0;animation-name:ck-upload-complete-icon-check;animation-duration:0.5s;animation-delay:0.5s;animation-fill-mode:forwards;position:absolute;top:50%;left:25%;transform:scaleX(-1) rotate(135deg)}@media (prefers-reduced-motion:reduce){.ck-image-upload-complete-icon{animation-duration:0s}.ck-image-upload-complete-icon:after{opacity:1;width:0.3em;height:0.45em;animation:none}}.ck-image-upload-complete-icon{z-index:1}@keyframes ck-upload-complete-icon-show{from{opacity:0}to{opacity:1}}@keyframes ck-upload-complete-icon-hide{from{opacity:1}to{opacity:0}}@keyframes ck-upload-complete-icon-check{0%{opacity:1;width:0;height:0}33%{width:0.3em;height:0}100%{opacity:1;width:0.3em;height:0.45em}}:root{--ck-color-upload-placeholder-loader: #b3b3b3;--ck-upload-placeholder-loader-size: 32px;--ck-upload-placeholder-image-aspect-ratio: 2.8}.ck .ck-image-upload-placeholder{width:100%;margin:0}.ck .ck-image-upload-placeholder.image-inline{width:calc(2 * var(--ck-upload-placeholder-loader-size) * var(--ck-upload-placeholder-image-aspect-ratio))}.ck .ck-image-upload-placeholder img{aspect-ratio:var(--ck-upload-placeholder-image-aspect-ratio)}.ck .ck-upload-placeholder-loader{justify-content:center;align-items:center;width:100%;height:100%;display:flex;position:absolute;top:0}.ck .ck-upload-placeholder-loader:before{width:var(--ck-upload-placeholder-loader-size);height:var(--ck-upload-placeholder-loader-size);border-top:3px solid var(--ck-color-upload-placeholder-loader);content:"";border-right:2px solid #0000;border-radius:50%;animation:1s linear infinite ck-upload-placeholder-loader;position:relative}.ck .ck-upload-placeholder-loader{left:0}@keyframes ck-upload-placeholder-loader{to{transform:rotate(360deg)}}.ck-content .image,.ibo-is-html-content .image{clear:both;text-align:center;min-width:50px;margin:0.9em auto;display:table}.ck-content .image img,.ibo-is-html-content .image img{min-width:100%;max-width:100%;height:auto;margin:0 auto;display:block}.ck-content .image-inline,.ibo-is-html-content .image-inline{align-items:flex-start;max-width:100%;display:inline-flex}.ck-content .image-inline picture,.ibo-is-html-content .image-inline picture{display:flex}.ck-content .image-inline picture,.ibo-is-html-content .image-inline picture,.ck-content .image-inline img,.ibo-is-html-content .image-inline img{flex-grow:1;flex-shrink:1;max-width:100%}.ck.ck-editor__editable .image>figcaption.ck-placeholder:before{padding-left:inherit;padding-right:inherit;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.ck.ck-editor__editable .image{z-index:1}.ck.ck-editor__editable .image.ck-widget_selected{z-index:2}.ck.ck-editor__editable .image-inline{z-index:1}.ck.ck-editor__editable .image-inline.ck-widget_selected{z-index:2}.ck.ck-editor__editable .image-inline.ck-widget_selected ::selection{display:none}.ck.ck-editor__editable .image-inline img{height:auto}:is(.ck.ck-editor__editable td, .ck.ck-editor__editable th) .image-inline img{max-width:none}.ck.ck-editor__editable img.image_placeholder{background-size:100% 100%}:root{--ck-image-insert-insert-by-url-width: 250px}.ck.ck-image-insert-url{--ck-input-width: 100%;width:400px}.ck.ck-image-insert-url .ck-image-insert-url__action-row{grid-column-gap:var(--ck-spacing-large);margin-top:var(--ck-spacing-large);display:grid}.ck.ck-image-insert-url .ck-image-insert-url__action-row .ck-button-save,.ck.ck-image-insert-url .ck-image-insert-url__action-row .ck-button-cancel{justify-content:center;min-width:auto}.ck.ck-image-insert-url .ck-image-insert-url__action-row .ck-button .ck-button__label{color:var(--ck-color-text)}.ck.ck-image-insert-url .ck-image-insert-url__action-row{grid-template-columns:repeat(2, 1fr)}.ck.ck-image-insert-url{padding:var(--ck-spacing-large) var(--ck-spacing-large) 0}.ck.ck-image-insert-form>.ck.ck-button{width:100%;display:block}[dir="ltr"] :is(.ck.ck-image-insert-form>.ck.ck-button){text-align:left}[dir="rtl"] :is(.ck.ck-image-insert-form>.ck.ck-button){text-align:right}.ck.ck-image-insert-form>.ck.ck-collapsible:not(:first-child){border-top:1px solid var(--ck-color-base-border)}.ck.ck-image-insert-form>.ck.ck-collapsible:not(:last-child){border-bottom:1px solid var(--ck-color-base-border)}.ck.ck-image-insert-form>.ck.ck-collapsible{min-width:var(--ck-image-insert-insert-by-url-width)}.ck.ck-image-insert-form>.ck.ck-image-insert-url{min-width:var(--ck-image-insert-insert-by-url-width);padding:var(--ck-spacing-large)}.ck.ck-image-insert-form:focus{outline:none}:root{--ck-image-custom-resize-form-width: 340px}@media screen and (width <= 600px){:root{--ck-image-custom-resize-form-width: 300px}}.ck.ck-image-custom-resize-form.ck-responsive-form{width:var(--ck-image-custom-resize-form-width)}:root{--ck-text-alternative-form-width: 340px}@media screen and (width <= 600px){:root{--ck-text-alternative-form-width: 300px}}.ck.ck-text-alternative-form.ck-responsive-form{width:var(--ck-text-alternative-form-width)}.ck .ck-link_selected{background:var(--ck-color-link-selected-background)}.ck .ck-link_selected span.image-inline{outline:var(--ck-widget-outline-thickness) solid var(--ck-color-link-selected-background)}.ck .ck-fake-link-selection{background:var(--ck-color-link-fake-selection)}.ck .ck-fake-link-selection_collapsed{border-right:1px solid var(--ck-color-base-text);outline:1px solid #ffffff80;height:100%;margin-right:-1px}:root{--ck-link-bookmark-icon-size: calc(var(--ck-icon-size) * .7)}.ck.ck-toolbar.ck-link-toolbar>.ck-toolbar__items{flex-wrap:nowrap}a.ck.ck-button.ck-link-toolbar__preview{padding:0 var(--ck-spacing-medium);color:var(--ck-color-link-default);cursor:pointer;justify-content:center}a.ck.ck-button.ck-link-toolbar__preview .ck.ck-button__label{text-overflow:ellipsis;max-width:var(--ck-input-width)}a.ck.ck-button.ck-link-toolbar__preview,a.ck.ck-button.ck-link-toolbar__preview:hover,a.ck.ck-button.ck-link-toolbar__preview:focus,a.ck.ck-button.ck-link-toolbar__preview:active{background:none}a.ck.ck-button.ck-link-toolbar__preview:active{box-shadow:none}a.ck.ck-button.ck-link-toolbar__preview:hover,a.ck.ck-button.ck-link-toolbar__preview:focus{text-decoration:underline}a.ck.ck-button.ck-link-toolbar__preview.ck-button_with-text .ck.ck-icon.ck-button__icon{width:var(--ck-link-bookmark-icon-size);height:var(--ck-link-bookmark-icon-size)}[dir="ltr"] :is(a.ck.ck-button.ck-link-toolbar__preview.ck-button_with-text .ck.ck-icon.ck-button__icon){margin-right:var(--ck-spacing-tiny);margin-left:var(--ck-spacing-small)}[dir="rtl"] :is(a.ck.ck-button.ck-link-toolbar__preview.ck-button_with-text .ck.ck-icon.ck-button__icon){margin-left:var(--ck-spacing-tiny);margin-right:var(--ck-spacing-small)}a.ck.ck-button.ck-link-toolbar__preview:has(.ck-icon){padding-left:var(--ck-spacing-extra-tiny)}.ck.ck-link-toolbar__preview{display:inline-block}.ck.ck-link-toolbar__preview .ck-button__label{overflow:hidden}:root{--ck-link-image-indicator-icon-size: 20;--ck-link-image-indicator-icon-is-visible: clamp(0px, 100% - 50px, 1px)}:is(.ck.ck-editor__editable figure.image>a, .ck.ck-editor__editable a span.image-inline):after{content:"";top:min(var(--ck-spacing-medium), 6%);right:min(var(--ck-spacing-medium), 6%);width:calc(var(--ck-link-image-indicator-icon-is-visible) * var(--ck-link-image-indicator-icon-size));height:calc(var(--ck-link-image-indicator-icon-is-visible) * var(--ck-link-image-indicator-icon-size));background-color:#0006;background-image:url("data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMjAgMjAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZmlsbD0iI2ZmZiIgZD0ibTExLjA3NyAxNSAuOTkxLTEuNDE2YS43NS43NSAwIDEgMSAxLjIyOS44NmwtMS4xNDggMS42NGEuNzQ4Ljc0OCAwIDAgMS0uMjE3LjIwNiA1LjI1MSA1LjI1MSAwIDAgMS04LjUwMy01Ljk1NS43NDEuNzQxIDAgMCAxIC4xMi0uMjc0bDEuMTQ3LTEuNjM5YS43NS43NSAwIDEgMSAxLjIyOC44Nkw0LjkzMyAxMC43bC4wMDYuMDAzYTMuNzUgMy43NSAwIDAgMCA2LjEzMiA0LjI5NGwuMDA2LjAwNHptNS40OTQtNS4zMzVhLjc0OC43NDggMCAwIDEtLjEyLjI3NGwtMS4xNDcgMS42MzlhLjc1Ljc1IDAgMSAxLTEuMjI4LS44NmwuODYtMS4yM2EzLjc1IDMuNzUgMCAwIDAtNi4xNDQtNC4zMDFsLS44NiAxLjIyOWEuNzUuNzUgMCAwIDEtMS4yMjktLjg2bDEuMTQ4LTEuNjRhLjc0OC43NDggMCAwIDEgLjIxNy0uMjA2IDUuMjUxIDUuMjUxIDAgMCAxIDguNTAzIDUuOTU1em0tNC41NjMtMi41MzJhLjc1Ljc1IDAgMCAxIC4xODQgMS4wNDVsLTMuMTU1IDQuNTA1YS43NS43NSAwIDEgMS0xLjIyOS0uODZsMy4xNTUtNC41MDZhLjc1Ljc1IDAgMCAxIDEuMDQ1LS4xODR6Ii8+PC9zdmc+");background-position:center;background-repeat:no-repeat;background-size:14px;border-radius:100%;display:block;position:absolute;overflow:hidden}:root{--ck-link-panel-width: 340px;--ck-link-provider-list-item-text-height: calc(var(--ck-line-height-base) * var(--ck-font-size-base));--ck-link-provider-list-item-height: calc(var(--ck-link-provider-list-item-text-height) + var(--ck-spacing-small) + var(--ck-spacing-small))}@media screen and (width <= 600px){:root{--ck-link-panel-width: 300px}}.ck.ck-form.ck-link-form{width:var(--ck-link-panel-width);padding-bottom:0}@media screen and (width <= 600px){.ck.ck-form.ck-link-form.ck-responsive-form .ck-labeled-field-view{margin:0}}.ck.ck-form.ck-link-form .ck-link-form__providers-list{border-top:1px solid var(--ck-color-base-border);flex-direction:column;display:flex}.ck.ck-form.ck-link-form .ck-link-form__providers-list:has(.ck-list__item:nth-child(n+5)){max-height:calc(var(--ck-link-provider-list-item-height) * 4 + var(--ck-spacing-large) + 1px);overflow:auto}.ck.ck-form.ck-link-form .ck-link-form__providers-list .ck-link__button{padding:var(--ck-spacing-small) var(--ck-spacing-large);border-radius:0}.ck.ck-form.ck-link-form .ck-link-form__providers-list .ck-link__button>.ck-button__label{text-overflow:ellipsis;flex-grow:1;overflow:hidden}.ck.ck-link-form .ck-link__items:empty{display:none}:root{--ck-link-properties-width: 340px}@media screen and (width <= 600px){:root{--ck-link-properties-width: 300px}}.ck.ck-link-properties{width:var(--ck-link-properties-width)}:root{--ck-link-providers-width: 340px;--ck-link-list-view-max-height: 240px;--ck-link-list-view-icon-size: calc(var(--ck-icon-size) * .8)}@media screen and (width <= 600px){:root{--ck-link-providers-width: 300px}}.ck.ck-link-providers{width:var(--ck-link-providers-width)}.ck.ck-link-providers .ck-form__header__label{text-overflow:ellipsis;overflow:hidden}.ck.ck-link-providers>.ck-link-providers__list{max-height:min(var(--ck-link-list-view-max-height), 40vh);overflow:hidden auto}.ck.ck-link-providers>.ck-link-providers__list .ck-button>.ck-icon{width:var(--ck-link-list-view-icon-size);height:var(--ck-link-list-view-icon-size);flex-shrink:0}.ck.ck-link-providers>.ck-link-providers__list .ck-button>.ck-button__label{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.ck.ck-link-providers>.ck-link-providers__list{overscroll-behavior:contain}.ck.ck-link-providers .ck-link__empty-list-info{padding:calc(2 * var(--ck-spacing-large)) var(--ck-spacing-medium);text-align:center;font-style:italic}.ck-editor__editable .ck-list-bogus-paragraph{display:block}:root{--ck-list-style-button-size: 44px}.ck.ck-list-styles-list{row-gap:var(--ck-spacing-medium);column-gap:var(--ck-spacing-medium);padding:var(--ck-spacing-large);grid-template-columns:repeat(3, auto)}.ck.ck-list-styles-list .ck-button{width:var(--ck-list-style-button-size);height:var(--ck-list-style-button-size);box-sizing:content-box;margin:0;padding:0}.ck.ck-list-styles-list .ck-button .ck-icon{width:var(--ck-list-style-button-size);height:var(--ck-list-style-button-size)}.ck.ck-list-styles-list{display:grid}.ck.ck-list-properties.ck-list-properties_without-styles{padding:var(--ck-spacing-large)}.ck.ck-list-properties.ck-list-properties_without-styles>*{min-width:14em}.ck.ck-list-properties.ck-list-properties_without-styles>*+*{margin-top:var(--ck-spacing-standard)}.ck.ck-list-properties.ck-list-properties_with-numbered-properties>.ck-list-styles-list{grid-template-columns:repeat(4, auto)}.ck.ck-list-properties.ck-list-properties_with-numbered-properties>.ck-collapsible{border-top:1px solid var(--ck-color-base-border)}.ck.ck-list-properties.ck-list-properties_with-numbered-properties>.ck-collapsible>.ck-collapsible__children>*{width:100%}.ck.ck-list-properties.ck-list-properties_with-numbered-properties>.ck-collapsible>.ck-collapsible__children>*+*{margin-top:var(--ck-spacing-standard)}.ck.ck-list-properties .ck.ck-numbered-list-properties__start-index .ck-input{width:100%;min-width:auto}.ck.ck-list-properties .ck.ck-numbered-list-properties__reversed-order{margin-bottom:calc(-1 * var(--ck-spacing-tiny));background:none;padding-left:0;padding-right:0}.ck.ck-list-properties .ck.ck-numbered-list-properties__reversed-order:active,.ck.ck-list-properties .ck.ck-numbered-list-properties__reversed-order:hover{box-shadow:none;background:none;border-color:#0000}:root{--ck-content-list-marker-color: var(--ck-content-font-color);--ck-content-list-marker-font-family: var(--ck-content-font-family);--ck-content-list-marker-font-size: var(--ck-content-font-size)}.ck-content li>p:first-of-type,.ibo-is-html-content li>p:first-of-type{margin-top:0}.ck-content li>p:only-of-type,.ibo-is-html-content li>p:only-of-type{margin-top:0;margin-bottom:0}.ck-content li.ck-list-marker-bold::marker,.ibo-is-html-content li.ck-list-marker-bold::marker{font-weight:bold}.ck-content li.ck-list-marker-italic::marker,.ibo-is-html-content li.ck-list-marker-italic::marker{font-style:italic}.ck-content li.ck-list-marker-color::marker,.ibo-is-html-content li.ck-list-marker-color::marker{color:var(--ck-content-list-marker-color)}.ck-content li.ck-list-marker-font-family::marker,.ibo-is-html-content li.ck-list-marker-font-family::marker{font-family:var(--ck-content-list-marker-font-family)}.ck-content li.ck-list-marker-font-size::marker,.ibo-is-html-content li.ck-list-marker-font-size::marker{font-size:var(--ck-content-list-marker-font-size)}.ck-content li.ck-list-marker-font-size-tiny::marker,.ibo-is-html-content li.ck-list-marker-font-size-tiny::marker{font-size:var(--ck-content-font-size-tiny)}.ck-content li.ck-list-marker-font-size-small::marker,.ibo-is-html-content li.ck-list-marker-font-size-small::marker{font-size:var(--ck-content-font-size-small)}.ck-content li.ck-list-marker-font-size-big::marker,.ibo-is-html-content li.ck-list-marker-font-size-big::marker{font-size:var(--ck-content-font-size-big)}.ck-content li.ck-list-marker-font-size-huge::marker,.ibo-is-html-content li.ck-list-marker-font-size-huge::marker{font-size:var(--ck-content-font-size-huge)}.ck-content ol,.ibo-is-html-content ol{list-style-type:decimal}.ck-content ol ol,.ibo-is-html-content ol ol{list-style-type:lower-latin}.ck-content ol ol ol,.ibo-is-html-content ol ol ol{list-style-type:lower-roman}.ck-content ol ol ol ol,.ibo-is-html-content ol ol ol ol{list-style-type:upper-latin}.ck-content ol ol ol ol ol,.ibo-is-html-content ol ol ol ol ol{list-style-type:upper-roman}.ck-content ul,.ibo-is-html-content ul{list-style-type:disc}.ck-content ul ul,.ibo-is-html-content ul ul{list-style-type:circle}.ck-content ul ul ul,.ibo-is-html-content ul ul ul{list-style-type:square}.ck-content ul ul ul ul,.ibo-is-html-content ul ul ul ul{list-style-type:square}:root{--ck-content-todo-list-checkmark-size: 16px}.ck-content .todo-list .todo-list__label>input,.ibo-is-html-content .todo-list .todo-list__label>input,.ck-editor__editable.ck-content .todo-list .todo-list__label>span[contenteditable="false"]>input,.ck-editor__editable.ibo-is-html-content .todo-list .todo-list__label>span[contenteditable="false"]>input{-webkit-appearance:none;width:var(--ck-content-todo-list-checkmark-size);height:var(--ck-content-todo-list-checkmark-size);vertical-align:middle;border:0;margin-left:0;margin-right:-15px;display:inline-block;position:relative;left:-25px;right:0}[dir="rtl"]:is(.ck-content .todo-list .todo-list__label>input, .ck-editor__editable.ck-content .todo-list .todo-list__label>span[contenteditable="false"]>input),[dir="rtl"]:is(.ibo-is-html-content .todo-list .todo-list__label>input, . ck-editor__editable . ck-content, . todo-list, . todo-list__label, >, span [ stringcontenteditable=string"false ], >, input),[dir="rtl"]:is(. ck-content, . todo-list, . todo-list__label, >, input, .ck-editor__editable.ibo-is-html-content .todo-list .todo-list__label>span[stringcontenteditable=string"false]>input){margin-left:-15px;margin-right:0;left:0;right:-25px}:is(.ck-content .todo-list .todo-list__label>input, .ck-editor__editable.ck-content .todo-list .todo-list__label>span[contenteditable="false"]>input):before,:is(.ibo-is-html-content .todo-list .todo-list__label>input, . ck-editor__editable . ck-content, . todo-list, . todo-list__label, >, span [ stringcontenteditable=string"false ], >, input):before,:is(. ck-content, . todo-list, . todo-list__label, >, input, .ck-editor__editable.ibo-is-html-content .todo-list .todo-list__label>span[stringcontenteditable=string"false]>input):before{box-sizing:border-box;content:"";border:1px solid #333;border-radius:2px;width:100%;height:100%;transition:box-shadow 0.25s ease-in-out;display:block;position:absolute}@media (prefers-reduced-motion:reduce){:is(.ck-content .todo-list .todo-list__label>input, .ck-editor__editable.ck-content .todo-list .todo-list__label>span[contenteditable="false"]>input):before,:is(.ibo-is-html-content .todo-list .todo-list__label>input, . ck-editor__editable . ck-content, . todo-list, . todo-list__label, >, span [ stringcontenteditable=string"false ], >, input):before,:is(. ck-content, . todo-list, . todo-list__label, >, input, .ck-editor__editable.ibo-is-html-content .todo-list .todo-list__label>span[stringcontenteditable=string"false]>input):before{transition:none}}:is(.ck-content .todo-list .todo-list__label>input, .ck-editor__editable.ck-content .todo-list .todo-list__label>span[contenteditable="false"]>input):after,:is(.ibo-is-html-content .todo-list .todo-list__label>input, . ck-editor__editable . ck-content, . todo-list, . todo-list__label, >, span [ stringcontenteditable=string"false ], >, input):after,:is(. ck-content, . todo-list, . todo-list__label, >, input, .ck-editor__editable.ibo-is-html-content .todo-list .todo-list__label>span[stringcontenteditable=string"false]>input):after{box-sizing:content-box;pointer-events:none;content:"";left:calc(var(--ck-content-todo-list-checkmark-size) / 3);top:calc(var(--ck-content-todo-list-checkmark-size) / 5.3);width:calc(var(--ck-content-todo-list-checkmark-size) / 5.3);height:calc(var(--ck-content-todo-list-checkmark-size) / 2.6);border-style:solid;border-color:#0000;border-width:0 calc(var(--ck-content-todo-list-checkmark-size) / 8) calc(var(--ck-content-todo-list-checkmark-size) / 8) 0;display:block;position:absolute;transform:rotate(45deg)}:is(.ck-content .todo-list .todo-list__label>input, .ck-editor__editable.ck-content .todo-list .todo-list__label>span[contenteditable="false"]>input)[checked]:before,:is(.ibo-is-html-content .todo-list .todo-list__label>input, . ck-editor__editable . ck-content, . todo-list, . todo-list__label, >, span [ stringcontenteditable=string"false ], >, input)[checked]:before,:is(. ck-content, . todo-list, . todo-list__label, >, input, .ck-editor__editable.ibo-is-html-content .todo-list .todo-list__label>span[stringcontenteditable=string"false]>input)[checked]:before{background:#26ab33;border-color:#26ab33}:is(.ck-content .todo-list .todo-list__label>input, .ck-editor__editable.ck-content .todo-list .todo-list__label>span[contenteditable="false"]>input)[checked]:after,:is(.ibo-is-html-content .todo-list .todo-list__label>input, . ck-editor__editable . ck-content, . todo-list, . todo-list__label, >, span [ stringcontenteditable=string"false ], >, input)[checked]:after,:is(. ck-content, . todo-list, . todo-list__label, >, input, .ck-editor__editable.ibo-is-html-content .todo-list .todo-list__label>span[stringcontenteditable=string"false]>input)[checked]:after{border-color:#fff}.ck-content .todo-list,.ibo-is-html-content .todo-list{list-style:none}.ck-content .todo-list li,.ibo-is-html-content .todo-list li{margin-bottom:5px;position:relative}.ck-content .todo-list li .todo-list,.ibo-is-html-content .todo-list li .todo-list{margin-top:5px}.ck-content .todo-list .todo-list__label .todo-list__label__description,.ibo-is-html-content .todo-list .todo-list__label .todo-list__label__description{vertical-align:middle}.ck-content .todo-list .todo-list__label.todo-list__label_without-description input[type="checkbox"],.ibo-is-html-content .todo-list .todo-list__label.todo-list__label_without-description input[type="checkbox"]{position:absolute}.ck-editor__editable.ck-content .todo-list .todo-list__label>input,.ck-editor__editable.ibo-is-html-content .todo-list .todo-list__label>input,.ck-editor__editable.ck-content .todo-list .todo-list__label>span[contenteditable="false"]>input,.ck-editor__editable.ibo-is-html-content .todo-list .todo-list__label>span[contenteditable="false"]>input{cursor:pointer}:is(.ck-editor__editable.ck-content .todo-list .todo-list__label>input, .ck-editor__editable.ck-content .todo-list .todo-list__label>span[contenteditable="false"]>input):hover:before,:is(.ck-editor__editable.ibo-is-html-content .todo-list .todo-list__label>input, . ck-editor__editable . ck-content, . todo-list, . todo-list__label, >, span [ stringcontenteditable=string"false ], >, input):hover:before,:is(. ck-editor__editable . ck-content, . todo-list, . todo-list__label, >, input, .ck-editor__editable.ibo-is-html-content .todo-list .todo-list__label>span[stringcontenteditable=string"false]>input):hover:before{box-shadow:0 0 0 5px #0000001a}.ck-editor__editable.ck-content .todo-list .todo-list__label.todo-list__label_without-description input[type="checkbox"],.ck-editor__editable.ibo-is-html-content .todo-list .todo-list__label.todo-list__label_without-description input[type="checkbox"]{position:absolute}.ck-content .media,.ibo-is-html-content .media{clear:both;min-width:15em;margin:0.9em 0;display:block}:root{--ck-media-embed-placeholder-icon-size: 3em;--ck-color-media-embed-placeholder-url-text: #757575;--ck-color-media-embed-placeholder-url-text-hover: var(--ck-color-base-text)}.ck-media__wrapper{margin:0 auto}.ck-media__wrapper .ck-media__placeholder{padding:calc(3 * var(--ck-spacing-standard));background:var(--ck-color-base-foreground);flex-direction:column;align-items:center;display:flex}.ck-media__wrapper .ck-media__placeholder .ck-media__placeholder__icon{min-width:var(--ck-media-embed-placeholder-icon-size);height:var(--ck-media-embed-placeholder-icon-size);margin-bottom:var(--ck-spacing-large);background-position:center;background-size:cover}.ck-media__wrapper .ck-media__placeholder .ck-media__placeholder__icon .ck-icon{width:100%;height:100%}.ck-media__wrapper .ck-media__placeholder .ck-media__placeholder__url__text{color:var(--ck-color-media-embed-placeholder-url-text);white-space:nowrap;text-align:center;text-overflow:ellipsis;font-style:italic}.ck-media__wrapper .ck-media__placeholder .ck-media__placeholder__url__text:hover{color:var(--ck-color-media-embed-placeholder-url-text-hover);cursor:pointer;text-decoration:underline}.ck-media__wrapper .ck-media__placeholder .ck-media__placeholder__url{max-width:100%;position:relative}.ck-media__wrapper .ck-media__placeholder .ck-media__placeholder__url .ck-media__placeholder__url__text{display:block;overflow:hidden}.ck-media__wrapper[data-oembed-url*="open.spotify.com"]{max-width:300px;max-height:380px}.ck-media__wrapper[data-oembed-url*="google.com/maps"] .ck-media__placeholder__icon,.ck-media__wrapper[data-oembed-url*="goo.gl/maps"] .ck-media__placeholder__icon,.ck-media__wrapper[data-oembed-url*="maps.google.com"] .ck-media__placeholder__icon,.ck-media__wrapper[data-oembed-url*="maps.app.goo.gl"] .ck-media__placeholder__icon{background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNTAuMzc4IiBoZWlnaHQ9IjI1NC4xNjciIHZpZXdCb3g9IjAgMCA2Ni4yNDYgNjcuMjQ4Ij48ZyB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMTcyLjUzMSAtMjE4LjQ1NSkgc2NhbGUoLjk4MDEyKSI+PHJlY3Qgcnk9IjUuMjM4IiByeD0iNS4yMzgiIHk9IjIzMS4zOTkiIHg9IjE3Ni4wMzEiIGhlaWdodD0iNjAuMDk5IiB3aWR0aD0iNjAuMDk5IiBmaWxsPSIjMzRhNjY4IiBwYWludC1vcmRlcj0ibWFya2VycyBzdHJva2UgZmlsbCIvPjxwYXRoIGQ9Ik0yMDYuNDc3IDI2MC45bC0yOC45ODcgMjguOTg3YTUuMjE4IDUuMjE4IDAgMCAwIDMuNzggMS42MWg0OS42MjFjMS42OTQgMCAzLjE5LS43OTggNC4xNDYtMi4wMzd6IiBmaWxsPSIjNWM4OGM1Ii8+PHBhdGggZD0iTTIyNi43NDIgMjIyLjk4OGMtOS4yNjYgMC0xNi43NzcgNy4xNy0xNi43NzcgMTYuMDE0LjAwNyAyLjc2Mi42NjMgNS40NzQgMi4wOTMgNy44NzUuNDMuNzAzLjgzIDEuNDA4IDEuMTkgMi4xMDcuMzMzLjUwMi42NSAxLjAwNS45NSAxLjUwOC4zNDMuNDc3LjY3My45NTcuOTg4IDEuNDQgMS4zMSAxLjc2OSAyLjUgMy41MDIgMy42MzcgNS4xNjguNzkzIDEuMjc1IDEuNjgzIDIuNjQgMi40NjYgMy45OSAyLjM2MyA0LjA5NCA0LjAwNyA4LjA5MiA0LjYgMTMuOTE0di4wMTJjLjE4Mi40MTIuNTE2LjY2Ni44NzkuNjY3LjQwMy0uMDAxLjc2OC0uMzE0LjkzLS43OTkuNjAzLTUuNzU2IDIuMjM4LTkuNzI5IDQuNTg1LTEzLjc5NC43ODItMS4zNSAxLjY3My0yLjcxNSAyLjQ2NS0zLjk5IDEuMTM3LTEuNjY2IDIuMzI4LTMuNCAzLjYzOC01LjE2OS4zMTUtLjQ4Mi42NDUtLjk2Mi45ODgtMS40MzkuMy0uNTAzLjYxNy0xLjAwNi45NS0xLjUwOC4zNTktLjcuNzYtMS40MDQgMS4xOS0yLjEwNyAxLjQyNi0yLjQwMiAyLTUuMTE0IDIuMDA0LTcuODc1IDAtOC44NDQtNy41MTEtMTYuMDE0LTE2Ljc3Ni0xNi4wMTR6IiBmaWxsPSIjZGQ0YjNlIiBwYWludC1vcmRlcj0ibWFya2VycyBzdHJva2UgZmlsbCIvPjxlbGxpcHNlIHJ5PSI1LjU2NCIgcng9IjUuODI4IiBjeT0iMjM5LjAwMiIgY3g9IjIyNi43NDIiIGZpbGw9IiM4MDJkMjciIHBhaW50LW9yZGVyPSJtYXJrZXJzIHN0cm9rZSBmaWxsIi8+PHBhdGggZD0iTTE5MC4zMDEgMjM3LjI4M2MtNC42NyAwLTguNDU3IDMuODUzLTguNDU3IDguNjA2czMuNzg2IDguNjA3IDguNDU3IDguNjA3YzMuMDQzIDAgNC44MDYtLjk1OCA2LjMzNy0yLjUxNiAxLjUzLTEuNTU3IDIuMDg3LTMuOTEzIDIuMDg3LTYuMjkgMC0uMzYyLS4wMjMtLjcyMi0uMDY0LTEuMDc5aC04LjI1N3YzLjA0M2g0Ljg1Yy0uMTk3Ljc1OS0uNTMxIDEuNDUtMS4wNTggMS45ODYtLjk0Mi45NTgtMi4wMjggMS41NDgtMy45MDEgMS41NDgtMi44NzYgMC01LjIwOC0yLjM3Mi01LjIwOC01LjI5OSAwLTIuOTI2IDIuMzMyLTUuMjk5IDUuMjA4LTUuMjk5IDEuMzk5IDAgMi42MTguNDA3IDMuNTg0IDEuMjkzbDIuMzgxLTIuMzhjMC0uMDAyLS4wMDMtLjAwNC0uMDA0LS4wMDUtMS41ODgtMS41MjQtMy42Mi0yLjIxNS01Ljk1NS0yLjIxNXptNC40MyA1LjY2bC4wMDMuMDA2di0uMDAzeiIgZmlsbD0iI2ZmZiIgcGFpbnQtb3JkZXI9Im1hcmtlcnMgc3Ryb2tlIGZpbGwiLz48cGF0aCBkPSJNMjE1LjE4NCAyNTEuOTI5bC03Ljk4IDcuOTc5IDI4LjQ3NyAyOC40NzVjLjI4Ny0uNjQ5LjQ0OS0xLjM2Ni40NDktMi4xMjN2LTMxLjE2NWMtLjQ2OS42NzUtLjkzNCAxLjM0OS0xLjM4MiAyLjAwNS0uNzkyIDEuMjc1LTEuNjgyIDIuNjQtMi40NjUgMy45OS0yLjM0NyA0LjA2NS0zLjk4MiA4LjAzOC00LjU4NSAxMy43OTQtLjE2Mi40ODUtLjUyNy43OTgtLjkzLjc5OS0uMzYzLS4wMDEtLjY5Ny0uMjU1LS44NzktLjY2N3YtLjAxMmMtLjU5My01LjgyMi0yLjIzNy05LjgyLTQuNi0xMy45MTQtLjc4My0xLjM1LTEuNjczLTIuNzE1LTIuNDY2LTMuOTktMS4xMzctMS42NjYtMi4zMjctMy40LTMuNjM3LTUuMTY5bC0uMDAyLS4wMDN6IiBmaWxsPSIjYzNjM2MzIi8+PHBhdGggZD0iTTIxMi45ODMgMjQ4LjQ5NWwtMzYuOTUyIDM2Ljk1M3YuODEyYTUuMjI3IDUuMjI3IDAgMCAwIDUuMjM4IDUuMjM4aDEuMDE1bDM1LjY2Ni0zNS42NjZhMTM2LjI3NSAxMzYuMjc1IDAgMCAwLTIuNzY0LTMuOSAzNy41NzUgMzcuNTc1IDAgMCAwLS45ODktMS40NGMtLjI5OS0uNTAzLS42MTYtMS4wMDYtLjk1LTEuNTA4LS4wODMtLjE2Mi0uMTc2LS4zMjYtLjI2NC0uNDg5eiIgZmlsbD0iI2ZkZGM0ZiIgcGFpbnQtb3JkZXI9Im1hcmtlcnMgc3Ryb2tlIGZpbGwiLz48cGF0aCBkPSJNMjExLjk5OCAyNjEuMDgzbC02LjE1MiA2LjE1MSAyNC4yNjQgMjQuMjY0aC43ODFhNS4yMjcgNS4yMjcgMCAwIDAgNS4yMzktNS4yMzh2LTEuMDQ1eiIgZmlsbD0iI2ZmZiIgcGFpbnQtb3JkZXI9Im1hcmtlcnMgc3Ryb2tlIGZpbGwiLz48L2c+PC9zdmc+")}.ck-media__wrapper[data-oembed-url*="facebook.com"] .ck-media__placeholder{background:#4268b3}.ck-media__wrapper[data-oembed-url*="facebook.com"] .ck-media__placeholder .ck-media__placeholder__icon{background-image:url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHdpZHRoPSIxMDI0cHgiIGhlaWdodD0iMTAyNHB4IiB2aWV3Qm94PSIwIDAgMTAyNCAxMDI0IiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPiAgICAgICAgPHRpdGxlPkZpbGwgMTwvdGl0bGU+ICAgIDxkZXNjPkNyZWF0ZWQgd2l0aCBTa2V0Y2guPC9kZXNjPiAgICA8ZGVmcz48L2RlZnM+ICAgIDxnIGlkPSJQYWdlLTEiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIiBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPiAgICAgICAgPGcgaWQ9ImZMb2dvX1doaXRlIiBmaWxsPSIjRkZGRkZFIj4gICAgICAgICAgICA8cGF0aCBkPSJNOTY3LjQ4NCwwIEw1Ni41MTcsMCBDMjUuMzA0LDAgMCwyNS4zMDQgMCw1Ni41MTcgTDAsOTY3LjQ4MyBDMCw5OTguNjk0IDI1LjI5NywxMDI0IDU2LjUyMiwxMDI0IEw1NDcsMTAyNCBMNTQ3LDYyOCBMNDE0LDYyOCBMNDE0LDQ3MyBMNTQ3LDQ3MyBMNTQ3LDM1OS4wMjkgQzU0NywyMjYuNzY3IDYyNy43NzMsMTU0Ljc0NyA3NDUuNzU2LDE1NC43NDcgQzgwMi4yNjksMTU0Ljc0NyA4NTAuODQyLDE1OC45NTUgODY1LDE2MC44MzYgTDg2NSwyOTkgTDc4My4zODQsMjk5LjAzNyBDNzE5LjM5MSwyOTkuMDM3IDcwNywzMjkuNTI5IDcwNywzNzQuMjczIEw3MDcsNDczIEw4NjAuNDg3LDQ3MyBMODQwLjUwMSw2MjggTDcwNyw2MjggTDcwNywxMDI0IEw5NjcuNDg0LDEwMjQgQzk5OC42OTcsMTAyNCAxMDI0LDk5OC42OTcgMTAyNCw5NjcuNDg0IEwxMDI0LDU2LjUxNSBDMTAyNCwyNS4zMDMgOTk4LjY5NywwIDk2Ny40ODQsMCIgaWQ9IkZpbGwtMSI+PC9wYXRoPiAgICAgICAgPC9nPiAgICA8L2c+PC9zdmc+")}.ck-media__wrapper[data-oembed-url*="facebook.com"] .ck-media__placeholder .ck-media__placeholder__url__text{color:#cdf}.ck-media__wrapper[data-oembed-url*="facebook.com"] .ck-media__placeholder .ck-media__placeholder__url__text:hover{color:#fff}.ck-media__wrapper[data-oembed-url*="instagram.com"] .ck-media__placeholder{background:linear-gradient(-135deg, #1400c7, #b800b1, #f50000)}.ck-media__wrapper[data-oembed-url*="instagram.com"] .ck-media__placeholder .ck-media__placeholder__icon{background-image:url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHdpZHRoPSI1MDRweCIgaGVpZ2h0PSI1MDRweCIgdmlld0JveD0iMCAwIDUwNCA1MDQiIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+ICAgICAgICA8dGl0bGU+Z2x5cGgtbG9nb19NYXkyMDE2PC90aXRsZT4gICAgPGRlc2M+Q3JlYXRlZCB3aXRoIFNrZXRjaC48L2Rlc2M+ICAgIDxkZWZzPiAgICAgICAgPHBvbHlnb24gaWQ9InBhdGgtMSIgcG9pbnRzPSIwIDAuMTU5IDUwMy44NDEgMC4xNTkgNTAzLjg0MSA1MDMuOTQgMCA1MDMuOTQiPjwvcG9seWdvbj4gICAgPC9kZWZzPiAgICA8ZyBpZD0iZ2x5cGgtbG9nb19NYXkyMDE2IiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4gICAgICAgIDxnIGlkPSJHcm91cC0zIj4gICAgICAgICAgICA8bWFzayBpZD0ibWFzay0yIiBmaWxsPSJ3aGl0ZSI+ICAgICAgICAgICAgICAgIDx1c2UgeGxpbms6aHJlZj0iI3BhdGgtMSI+PC91c2U+ICAgICAgICAgICAgPC9tYXNrPiAgICAgICAgICAgIDxnIGlkPSJDbGlwLTIiPjwvZz4gICAgICAgICAgICA8cGF0aCBkPSJNMjUxLjkyMSwwLjE1OSBDMTgzLjUwMywwLjE1OSAxNzQuOTI0LDAuNDQ5IDE0OC4wNTQsMS42NzUgQzEyMS4yNCwyLjg5OCAxMDIuOTI3LDcuMTU3IDg2LjkwMywxMy4zODUgQzcwLjMzNywxOS44MjIgNTYuMjg4LDI4LjQzNiA0Mi4yODIsNDIuNDQxIEMyOC4yNzcsNTYuNDQ3IDE5LjY2Myw3MC40OTYgMTMuMjI2LDg3LjA2MiBDNi45OTgsMTAzLjA4NiAyLjczOSwxMjEuMzk5IDEuNTE2LDE0OC4yMTMgQzAuMjksMTc1LjA4MyAwLDE4My42NjIgMCwyNTIuMDggQzAsMzIwLjQ5NyAwLjI5LDMyOS4wNzYgMS41MTYsMzU1Ljk0NiBDMi43MzksMzgyLjc2IDYuOTk4LDQwMS4wNzMgMTMuMjI2LDQxNy4wOTcgQzE5LjY2Myw0MzMuNjYzIDI4LjI3Nyw0NDcuNzEyIDQyLjI4Miw0NjEuNzE4IEM1Ni4yODgsNDc1LjcyMyA3MC4zMzcsNDg0LjMzNyA4Ni45MDMsNDkwLjc3NSBDMTAyLjkyNyw0OTcuMDAyIDEyMS4yNCw1MDEuMjYxIDE0OC4wNTQsNTAyLjQ4NCBDMTc0LjkyNCw1MDMuNzEgMTgzLjUwMyw1MDQgMjUxLjkyMSw1MDQgQzMyMC4zMzgsNTA0IDMyOC45MTcsNTAzLjcxIDM1NS43ODcsNTAyLjQ4NCBDMzgyLjYwMSw1MDEuMjYxIDQwMC45MTQsNDk3LjAwMiA0MTYuOTM4LDQ5MC43NzUgQzQzMy41MDQsNDg0LjMzNyA0NDcuNTUzLDQ3NS43MjMgNDYxLjU1OSw0NjEuNzE4IEM0NzUuNTY0LDQ0Ny43MTIgNDg0LjE3OCw0MzMuNjYzIDQ5MC42MTYsNDE3LjA5NyBDNDk2Ljg0Myw0MDEuMDczIDUwMS4xMDIsMzgyLjc2IDUwMi4zMjUsMzU1Ljk0NiBDNTAzLjU1MSwzMjkuMDc2IDUwMy44NDEsMzIwLjQ5NyA1MDMuODQxLDI1Mi4wOCBDNTAzLjg0MSwxODMuNjYyIDUwMy41NTEsMTc1LjA4MyA1MDIuMzI1LDE0OC4yMTMgQzUwMS4xMDIsMTIxLjM5OSA0OTYuODQzLDEwMy4wODYgNDkwLjYxNiw4Ny4wNjIgQzQ4NC4xNzgsNzAuNDk2IDQ3NS41NjQsNTYuNDQ3IDQ2MS41NTksNDIuNDQxIEM0NDcuNTUzLDI4LjQzNiA0MzMuNTA0LDE5LjgyMiA0MTYuOTM4LDEzLjM4NSBDNDAwLjkxNCw3LjE1NyAzODIuNjAxLDIuODk4IDM1NS43ODcsMS42NzUgQzMyOC45MTcsMC40NDkgMzIwLjMzOCwwLjE1OSAyNTEuOTIxLDAuMTU5IFogTTI1MS45MjEsNDUuNTUgQzMxOS4xODYsNDUuNTUgMzI3LjE1NCw0NS44MDcgMzUzLjcxOCw0Ny4wMTkgQzM3OC4yOCw0OC4xMzkgMzkxLjYxOSw1Mi4yNDMgNDAwLjQ5Niw1NS42OTMgQzQxMi4yNTUsNjAuMjYzIDQyMC42NDcsNjUuNzIyIDQyOS40NjIsNzQuNTM4IEM0MzguMjc4LDgzLjM1MyA0NDMuNzM3LDkxLjc0NSA0NDguMzA3LDEwMy41MDQgQzQ1MS43NTcsMTEyLjM4MSA0NTUuODYxLDEyNS43MiA0NTYuOTgxLDE1MC4yODIgQzQ1OC4xOTMsMTc2Ljg0NiA0NTguNDUsMTg0LjgxNCA0NTguNDUsMjUyLjA4IEM0NTguNDUsMzE5LjM0NSA0NTguMTkzLDMyNy4zMTMgNDU2Ljk4MSwzNTMuODc3IEM0NTUuODYxLDM3OC40MzkgNDUxLjc1NywzOTEuNzc4IDQ0OC4zMDcsNDAwLjY1NSBDNDQzLjczNyw0MTIuNDE0IDQzOC4yNzgsNDIwLjgwNiA0MjkuNDYyLDQyOS42MjEgQzQyMC42NDcsNDM4LjQzNyA0MTIuMjU1LDQ0My44OTYgNDAwLjQ5Niw0NDguNDY2IEMzOTEuNjE5LDQ1MS45MTYgMzc4LjI4LDQ1Ni4wMiAzNTMuNzE4LDQ1Ny4xNCBDMzI3LjE1OCw0NTguMzUyIDMxOS4xOTEsNDU4LjYwOSAyNTEuOTIxLDQ1OC42MDkgQzE4NC42NSw0NTguNjA5IDE3Ni42ODQsNDU4LjM1MiAxNTAuMTIzLDQ1Ny4xNCBDMTI1LjU2MSw0NTYuMDIgMTEyLjIyMiw0NTEuOTE2IDEwMy4zNDUsNDQ4LjQ2NiBDOTEuNTg2LDQ0My44OTYgODMuMTk0LDQzOC40MzcgNzQuMzc5LDQyOS42MjEgQzY1LjU2NCw0MjAuODA2IDYwLjEwNCw0MTIuNDE0IDU1LjUzNCw0MDAuNjU1IEM1Mi4wODQsMzkxLjc3OCA0Ny45OCwzNzguNDM5IDQ2Ljg2LDM1My44NzcgQzQ1LjY0OCwzMjcuMzEzIDQ1LjM5MSwzMTkuMzQ1IDQ1LjM5MSwyNTIuMDggQzQ1LjM5MSwxODQuODE0IDQ1LjY0OCwxNzYuODQ2IDQ2Ljg2LDE1MC4yODIgQzQ3Ljk4LDEyNS43MiA1Mi4wODQsMTEyLjM4MSA1NS41MzQsMTAzLjUwNCBDNjAuMTA0LDkxLjc0NSA2NS41NjMsODMuMzUzIDc0LjM3OSw3NC41MzggQzgzLjE5NCw2NS43MjIgOTEuNTg2LDYwLjI2MyAxMDMuMzQ1LDU1LjY5MyBDMTEyLjIyMiw1Mi4yNDMgMTI1LjU2MSw0OC4xMzkgMTUwLjEyMyw0Ny4wMTkgQzE3Ni42ODcsNDUuODA3IDE4NC42NTUsNDUuNTUgMjUxLjkyMSw0NS41NSBaIiBpZD0iRmlsbC0xIiBmaWxsPSIjRkZGRkZGIiBtYXNrPSJ1cmwoI21hc2stMikiPjwvcGF0aD4gICAgICAgIDwvZz4gICAgICAgIDxwYXRoIGQ9Ik0yNTEuOTIxLDMzNi4wNTMgQzIwNS41NDMsMzM2LjA1MyAxNjcuOTQ3LDI5OC40NTcgMTY3Ljk0NywyNTIuMDggQzE2Ny45NDcsMjA1LjcwMiAyMDUuNTQzLDE2OC4xMDYgMjUxLjkyMSwxNjguMTA2IEMyOTguMjk4LDE2OC4xMDYgMzM1Ljg5NCwyMDUuNzAyIDMzNS44OTQsMjUyLjA4IEMzMzUuODk0LDI5OC40NTcgMjk4LjI5OCwzMzYuMDUzIDI1MS45MjEsMzM2LjA1MyBaIE0yNTEuOTIxLDEyMi43MTUgQzE4MC40NzQsMTIyLjcxNSAxMjIuNTU2LDE4MC42MzMgMTIyLjU1NiwyNTIuMDggQzEyMi41NTYsMzIzLjUyNiAxODAuNDc0LDM4MS40NDQgMjUxLjkyMSwzODEuNDQ0IEMzMjMuMzY3LDM4MS40NDQgMzgxLjI4NSwzMjMuNTI2IDM4MS4yODUsMjUyLjA4IEMzODEuMjg1LDE4MC42MzMgMzIzLjM2NywxMjIuNzE1IDI1MS45MjEsMTIyLjcxNSBaIiBpZD0iRmlsbC00IiBmaWxsPSIjRkZGRkZGIj48L3BhdGg+ICAgICAgICA8cGF0aCBkPSJNNDE2LjYyNywxMTcuNjA0IEM0MTYuNjI3LDEzNC4zIDQwMy4wOTIsMTQ3LjgzNCAzODYuMzk2LDE0Ny44MzQgQzM2OS43MDEsMTQ3LjgzNCAzNTYuMTY2LDEzNC4zIDM1Ni4xNjYsMTE3LjYwNCBDMzU2LjE2NiwxMDAuOTA4IDM2OS43MDEsODcuMzczIDM4Ni4zOTYsODcuMzczIEM0MDMuMDkyLDg3LjM3MyA0MTYuNjI3LDEwMC45MDggNDE2LjYyNywxMTcuNjA0IiBpZD0iRmlsbC01IiBmaWxsPSIjRkZGRkZGIj48L3BhdGg+ICAgIDwvZz48L3N2Zz4=")}.ck-media__wrapper[data-oembed-url*="instagram.com"] .ck-media__placeholder .ck-media__placeholder__url__text{color:#ffe0fe}.ck-media__wrapper[data-oembed-url*="instagram.com"] .ck-media__placeholder .ck-media__placeholder__url__text:hover{color:#fff}.ck-media__wrapper[data-oembed-url*="twitter.com"] .ck.ck-media__placeholder{background:linear-gradient(to right, #71c6f4, #0d70a5)}.ck-media__wrapper[data-oembed-url*="twitter.com"] .ck.ck-media__placeholder .ck-media__placeholder__icon{background-image:url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIHZlcnNpb249IjEuMSIgaWQ9IldoaXRlIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDQwMCA0MDAiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDQwMCA0MDA7IiB4bWw6c3BhY2U9InByZXNlcnZlIj48c3R5bGUgdHlwZT0idGV4dC9jc3MiPi5zdDB7ZmlsbDojRkZGRkZGO308L3N0eWxlPjxwYXRoIGNsYXNzPSJzdDAiIGQ9Ik00MDAsMjAwYzAsMTEwLjUtODkuNSwyMDAtMjAwLDIwMFMwLDMxMC41LDAsMjAwUzg5LjUsMCwyMDAsMFM0MDAsODkuNSw0MDAsMjAweiBNMTYzLjQsMzA1LjVjODguNywwLDEzNy4yLTczLjUsMTM3LjItMTM3LjJjMC0yLjEsMC00LjItMC4xLTYuMmM5LjQtNi44LDE3LjYtMTUuMywyNC4xLTI1Yy04LjYsMy44LTE3LjksNi40LTI3LjcsNy42YzEwLTYsMTcuNi0xNS40LDIxLjItMjYuN2MtOS4zLDUuNS0xOS42LDkuNS0zMC42LDExLjdjLTguOC05LjQtMjEuMy0xNS4yLTM1LjItMTUuMmMtMjYuNiwwLTQ4LjIsMjEuNi00OC4yLDQ4LjJjMCwzLjgsMC40LDcuNSwxLjMsMTFjLTQwLjEtMi03NS42LTIxLjItOTkuNC01MC40Yy00LjEsNy4xLTYuNSwxNS40LTYuNSwyNC4yYzAsMTYuNyw4LjUsMzEuNSwyMS41LDQwLjFjLTcuOS0wLjItMTUuMy0yLjQtMjEuOC02YzAsMC4yLDAsMC40LDAsMC42YzAsMjMuNCwxNi42LDQyLjgsMzguNyw0Ny4zYy00LDEuMS04LjMsMS43LTEyLjcsMS43Yy0zLjEsMC02LjEtMC4zLTkuMS0wLjljNi4xLDE5LjIsMjMuOSwzMy4xLDQ1LDMzLjVjLTE2LjUsMTIuOS0zNy4zLDIwLjYtNTkuOSwyMC42Yy0zLjksMC03LjctMC4yLTExLjUtMC43QzExMC44LDI5Ny41LDEzNi4yLDMwNS41LDE2My40LDMwNS41Ii8+PC9zdmc+")}.ck-media__wrapper[data-oembed-url*="twitter.com"] .ck.ck-media__placeholder .ck-media__placeholder__url__text{color:#b8e6ff}.ck-media__wrapper[data-oembed-url*="twitter.com"] .ck.ck-media__placeholder .ck-media__placeholder__url__text:hover{color:#fff}:is(.ck-media__wrapper[data-oembed-url*="twitter.com"], .ck-media__wrapper[data-oembed-url*="google.com/maps"], .ck-media__wrapper[data-oembed-url*="goo.gl/maps"], .ck-media__wrapper[data-oembed-url*="maps.google.com"], .ck-media__wrapper[data-oembed-url*="maps.app.goo.gl"], .ck-media__wrapper[data-oembed-url*="facebook.com"], .ck-media__wrapper[data-oembed-url*="instagram.com"]) .ck-media__placeholder__icon *{display:none}.ck-editor__editable:not(.ck-read-only) .ck-media__wrapper>:not(.ck-media__placeholder),.ck-editor__editable:not(.ck-read-only) .ck-widget:not(.ck-widget_selected) .ck-media__placeholder{pointer-events:none}.ck.ck-media-form{flex-flow:row;align-items:flex-start;width:400px;display:flex}.ck.ck-media-form .ck-labeled-field-view{width:100%;display:inline-block}.ck.ck-media-form .ck-label{display:none}.ck.ck-media-form .ck-input{width:100%}@media screen and (width <= 600px){.ck.ck-media-form{flex-wrap:wrap}.ck.ck-media-form .ck-labeled-field-view{flex-basis:100%}.ck.ck-media-form .ck-button{flex-basis:50%}}:root{--ck-content-color-mention-background: #9900301a;--ck-content-color-mention-text: #990030}.ck-content .mention,.ibo-is-html-content .mention{background:var(--ck-content-color-mention-background);color:var(--ck-content-color-mention-text)}:root{--ck-mention-list-max-height: 300px}.ck.ck-mentions{max-height:var(--ck-mention-list-max-height);overscroll-behavior:contain;overflow:hidden auto}.ck.ck-mentions>.ck-list__item{flex-shrink:0;overflow:hidden}div.ck.ck-balloon-panel.ck-mention-balloon{z-index:calc(var(--ck-z-dialog) + 1)}:root{--ck-color-minimap-tracker-background: 208, 0%, 51%;--ck-color-minimap-iframe-outline: #bfbfbf;--ck-color-minimap-iframe-shadow: #0000001c;--ck-color-minimap-progress-background: #666}.ck.ck-minimap{user-select:none;background:var(--ck-color-base-background);position:absolute}.ck.ck-minimap,.ck.ck-minimap iframe{width:100%;height:100%}.ck.ck-minimap iframe{pointer-events:none;outline:1px solid var(--ck-color-minimap-iframe-outline);box-shadow:0 2px 5px var(--ck-color-minimap-iframe-shadow);border:0;margin:0;position:relative}.ck.ck-minimap .ck.ck-minimap__position-tracker{background:hsla(var(--ck-color-minimap-tracker-background), 0.2);z-index:1;width:100%;transition:background 0.1s ease-in-out;position:absolute;top:0}@media (prefers-reduced-motion:reduce){.ck.ck-minimap .ck.ck-minimap__position-tracker{transition:none}}.ck.ck-minimap .ck.ck-minimap__position-tracker:hover{background:hsla(var(--ck-color-minimap-tracker-background), 0.3)}.ck.ck-minimap .ck.ck-minimap__position-tracker.ck-minimap__position-tracker_dragging,.ck.ck-minimap .ck.ck-minimap__position-tracker.ck-minimap__position-tracker_dragging:hover{background:hsla(var(--ck-color-minimap-tracker-background), 0.4)}:is(.ck.ck-minimap .ck.ck-minimap__position-tracker.ck-minimap__position-tracker_dragging, .ck.ck-minimap .ck.ck-minimap__position-tracker.ck-minimap__position-tracker_dragging:hover):after{opacity:1}.ck.ck-minimap .ck.ck-minimap__position-tracker:after{content:attr(data-progress) "%";background:var(--ck-color-minimap-progress-background);color:var(--ck-color-base-background);border:1px solid var(--ck-color-base-background);opacity:0;border-radius:3px;padding:2px 4px;font-size:10px;transition:opacity 0.1s ease-in-out;position:absolute;top:5px;right:5px}@media (prefers-reduced-motion:reduce){.ck.ck-minimap .ck.ck-minimap__position-tracker:after{transition:none}}.ck-content .page-break,.ibo-is-html-content .page-break{clear:both;justify-content:center;align-items:center;padding:5px 0;display:flex;position:relative}.ck-content .page-break:after,.ibo-is-html-content .page-break:after{content:"";border-bottom:2px dashed #c4c4c4;width:100%;position:absolute}.ck-content .page-break__label,.ibo-is-html-content .page-break__label{z-index:1;text-transform:uppercase;color:#333;-webkit-user-select:none;user-select:none;background:#fff;border:1px solid #c4c4c4;border-radius:2px;padding:0.3em 0.6em;font-size:0.75em;font-weight:bold;display:block;position:relative;box-shadow:2px 2px 1px #00000026}@media print{.ck-content .page-break,.ibo-is-html-content .page-break{padding:0}.ck-content .page-break:after,.ibo-is-html-content .page-break:after{display:none}.ck-content :has(+ .page-break),.ibo-is-html-content :has(+ .page-break){margin-bottom:0}}:root{--ck-color-restricted-editing-exception-background: #ffa94c33;--ck-color-restricted-editing-exception-hover-background: #ffa94c59;--ck-color-restricted-editing-exception-brackets: #cc690066;--ck-color-restricted-editing-selected-exception-background: #ffa94c80;--ck-color-restricted-editing-selected-exception-brackets: #cc690099}.ck-editor__editable .restricted-editing-exception{background-color:var(--ck-color-restricted-editing-exception-background);border:1px solid;border-image:linear-gradient(to right, var(--ck-color-restricted-editing-exception-brackets) 0%, var(--ck-color-restricted-editing-exception-brackets) 5px, #0000 6px, #0000 calc(100% - 6px), var(--ck-color-restricted-editing-exception-brackets) calc(100% - 5px), var(--ck-color-restricted-editing-exception-brackets) 100%) 1;transition:background 0.2s ease-in-out}@media (prefers-reduced-motion:reduce){.ck-editor__editable .restricted-editing-exception{transition:none}}.ck-editor__editable .restricted-editing-exception.restricted-editing-exception_selected{background-color:var(--ck-color-restricted-editing-selected-exception-background);border-image:linear-gradient(to right, var(--ck-color-restricted-editing-selected-exception-brackets) 0%, var(--ck-color-restricted-editing-selected-exception-brackets) 5px, var(--ck-color-restricted-editing-selected-exception-brackets) calc(100% - 5px), var(--ck-color-restricted-editing-selected-exception-brackets) 100%) 1}.ck-editor__editable .restricted-editing-exception.restricted-editing-exception_collapsed{padding-left:1ch}.ck-restricted-editing_mode_restricted{cursor:default}.ck-restricted-editing_mode_restricted *{cursor:default}.ck-restricted-editing_mode_restricted .restricted-editing-exception{cursor:text}.ck-restricted-editing_mode_restricted .restricted-editing-exception *{cursor:text}.ck-restricted-editing_mode_restricted .restricted-editing-exception:hover{background:var(--ck-color-restricted-editing-exception-hover-background)}:root{--ck-show-blocks-border-color: #757575}.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) address{--ck-show-blocks-label-ltr: var(--ck-show-blocks-label-address-ltr);--ck-show-blocks-label-rtl: var(--ck-show-blocks-label-address-rtl)}.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) aside{--ck-show-blocks-label-ltr: var(--ck-show-blocks-label-aside-ltr);--ck-show-blocks-label-rtl: var(--ck-show-blocks-label-aside-rtl)}.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) blockquote{--ck-show-blocks-label-ltr: var(--ck-show-blocks-label-blockquote-ltr);--ck-show-blocks-label-rtl: var(--ck-show-blocks-label-blockquote-rtl)}.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) details{--ck-show-blocks-label-ltr: var(--ck-show-blocks-label-details-ltr);--ck-show-blocks-label-rtl: var(--ck-show-blocks-label-details-rtl)}.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) div:not(.ck-widget, .ck-widget *){--ck-show-blocks-label-ltr: var(--ck-show-blocks-label-div-ltr);--ck-show-blocks-label-rtl: var(--ck-show-blocks-label-div-rtl)}.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) footer{--ck-show-blocks-label-ltr: var(--ck-show-blocks-label-footer-ltr);--ck-show-blocks-label-rtl: var(--ck-show-blocks-label-footer-rtl)}.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) h1{--ck-show-blocks-label-ltr: var(--ck-show-blocks-label-h1-ltr);--ck-show-blocks-label-rtl: var(--ck-show-blocks-label-h1-rtl)}.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) h2{--ck-show-blocks-label-ltr: var(--ck-show-blocks-label-h2-ltr);--ck-show-blocks-label-rtl: var(--ck-show-blocks-label-h2-rtl)}.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) h3{--ck-show-blocks-label-ltr: var(--ck-show-blocks-label-h3-ltr);--ck-show-blocks-label-rtl: var(--ck-show-blocks-label-h3-rtl)}.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) h4{--ck-show-blocks-label-ltr: var(--ck-show-blocks-label-h4-ltr);--ck-show-blocks-label-rtl: var(--ck-show-blocks-label-h4-rtl)}.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) h5{--ck-show-blocks-label-ltr: var(--ck-show-blocks-label-h5-ltr);--ck-show-blocks-label-rtl: var(--ck-show-blocks-label-h5-rtl)}.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) h6{--ck-show-blocks-label-ltr: var(--ck-show-blocks-label-h6-ltr);--ck-show-blocks-label-rtl: var(--ck-show-blocks-label-h6-rtl)}.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) header{--ck-show-blocks-label-ltr: var(--ck-show-blocks-label-header-ltr);--ck-show-blocks-label-rtl: var(--ck-show-blocks-label-header-rtl)}.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) main{--ck-show-blocks-label-ltr: var(--ck-show-blocks-label-main-ltr);--ck-show-blocks-label-rtl: var(--ck-show-blocks-label-main-rtl)}.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) nav{--ck-show-blocks-label-ltr: var(--ck-show-blocks-label-nav-ltr);--ck-show-blocks-label-rtl: var(--ck-show-blocks-label-nav-rtl)}.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) pre{--ck-show-blocks-label-ltr: var(--ck-show-blocks-label-pre-ltr);--ck-show-blocks-label-rtl: var(--ck-show-blocks-label-pre-rtl)}.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) ol{--ck-show-blocks-label-ltr: var(--ck-show-blocks-label-ol-ltr);--ck-show-blocks-label-rtl: var(--ck-show-blocks-label-ol-rtl)}.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) ul{--ck-show-blocks-label-ltr: var(--ck-show-blocks-label-ul-ltr);--ck-show-blocks-label-rtl: var(--ck-show-blocks-label-ul-rtl)}.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) p{--ck-show-blocks-label-ltr: var(--ck-show-blocks-label-p-ltr);--ck-show-blocks-label-rtl: var(--ck-show-blocks-label-p-rtl)}.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) section{--ck-show-blocks-label-ltr: var(--ck-show-blocks-label-section-ltr);--ck-show-blocks-label-rtl: var(--ck-show-blocks-label-section-rtl)}.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) :where(figure.image, figure.table) figcaption{--ck-show-blocks-label-ltr: var(--ck-show-blocks-label-figcaption-ltr);--ck-show-blocks-label-rtl: var(--ck-show-blocks-label-figcaption-rtl)}.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) address,.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) aside,.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) blockquote,.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) details,.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) div:not(.ck-widget, .ck-widget *),.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) footer,.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) h1,.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) h2,.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) h3,.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) h4,.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) h5,.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) h6,.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) header,.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) main,.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) nav,.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) pre,.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) ol,.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) ul,.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) p,.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) section,.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) :where(figure.image, figure.table) figcaption{background-repeat:no-repeat;padding-top:15px}:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) address, .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) aside, .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) blockquote, .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) details, .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) div:not(.ck-widget, .ck-widget *), .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) footer, .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) h1, .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) h2, .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) h3, .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) h4, .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) h5, .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) h6, .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) header, .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) main, .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) nav, .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) pre, .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) ol, .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) ul, .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) p, .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) section, .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget) :where(figure.image, figure.table) figcaption):where(:not(.ck-widget_selected):not(.ck-widget:hover)){outline:1px dashed var(--ck-show-blocks-border-color)}:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="ltr"], [dir="ltr"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) address,:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="ltr"], [dir="ltr"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) aside,:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="ltr"], [dir="ltr"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) blockquote,:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="ltr"], [dir="ltr"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) details,:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="ltr"], [dir="ltr"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) div:not(.ck-widget, .ck-widget *),:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="ltr"], [dir="ltr"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) footer,:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="ltr"], [dir="ltr"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) h1,:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="ltr"], [dir="ltr"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) h2,:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="ltr"], [dir="ltr"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) h3,:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="ltr"], [dir="ltr"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) h4,:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="ltr"], [dir="ltr"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) h5,:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="ltr"], [dir="ltr"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) h6,:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="ltr"], [dir="ltr"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) header,:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="ltr"], [dir="ltr"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) main,:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="ltr"], [dir="ltr"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) nav,:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="ltr"], [dir="ltr"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) pre,:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="ltr"], [dir="ltr"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) ol,:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="ltr"], [dir="ltr"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) ul,:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="ltr"], [dir="ltr"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) p,:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="ltr"], [dir="ltr"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) section,:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="ltr"], [dir="ltr"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) :where(figure.image, figure.table) figcaption{background-image:var(--ck-show-blocks-label-ltr);background-position:1px 1px}:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="rtl"], [dir="rtl"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) address,:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="rtl"], [dir="rtl"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) aside,:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="rtl"], [dir="rtl"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) blockquote,:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="rtl"], [dir="rtl"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) details,:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="rtl"], [dir="rtl"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) div:not(.ck-widget, .ck-widget *),:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="rtl"], [dir="rtl"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) footer,:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="rtl"], [dir="rtl"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) h1,:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="rtl"], [dir="rtl"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) h2,:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="rtl"], [dir="rtl"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) h3,:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="rtl"], [dir="rtl"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) h4,:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="rtl"], [dir="rtl"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) h5,:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="rtl"], [dir="rtl"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) h6,:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="rtl"], [dir="rtl"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) header,:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="rtl"], [dir="rtl"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) main,:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="rtl"], [dir="rtl"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) nav,:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="rtl"], [dir="rtl"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) pre,:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="rtl"], [dir="rtl"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) ol,:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="rtl"], [dir="rtl"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) ul,:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="rtl"], [dir="rtl"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) p,:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="rtl"], [dir="rtl"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) section,:is(.ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)[dir="rtl"], [dir="rtl"] .ck.ck-editor__editable.ck-editor__editable_inline.ck-show-blocks:not(.ck-widget)) :where(figure.image, figure.table) figcaption{background-image:var(--ck-show-blocks-label-rtl);background-position:calc(100% - 1px) 1px}.ck-source-editing-area{position:relative;overflow:hidden}.ck-source-editing-area:after,.ck-source-editing-area textarea{padding:var(--ck-spacing-large);line-height:var(--ck-line-height-base);font-size:var(--ck-font-size-normal);white-space:pre-wrap;border:1px solid #0000;margin:0;font-family:monospace}.ck-source-editing-area:after{content:attr(data-value) " ";visibility:hidden;display:block}.ck-source-editing-area textarea{resize:none;box-sizing:border-box;border-color:var(--ck-color-base-border);border-radius:var(--ck-rounded-corners-radius);border-top-left-radius:0;border-top-right-radius:0;outline:none;width:100%;height:100%;position:absolute;overflow:hidden}.ck-source-editing-area textarea:not([readonly]):focus{border:var(--ck-focus-ring);box-shadow:var(--ck-inner-shadow), 0 0;outline:none}.ck.ck-special-characters-navigation>.ck-label{text-overflow:ellipsis;max-width:160px;overflow:hidden}.ck.ck-special-characters-navigation>.ck-dropdown .ck-dropdown__panel{max-height:250px;overflow:hidden auto}@media screen and (width <= 600px){.ck.ck-special-characters-navigation{max-width:190px}.ck.ck-special-characters-navigation>.ck-form__header__label{text-overflow:ellipsis;overflow:hidden}}.ck.ck-special-characters>.ck-dialog__content>div{grid-column-gap:0px;grid-row-gap:0px;grid-template-rows:auto 1fr auto;grid-template-columns:1fr;width:350px;max-width:100%;height:100%;display:grid}.ck.ck-special-characters>.ck-dialog__content>div>.ck-character-categories{padding:var(--ck-spacing-medium) var(--ck-spacing-large);grid-area:0.25}.ck.ck-special-characters>.ck-dialog__content>div>.ck-character-categories>.ck-labeled-field-view{padding-top:var(--ck-spacing-standard);width:100%}.ck.ck-special-characters>.ck-dialog__content>div>.ck-character-categories>.ck-labeled-field-view .ck.ck-labeled-field-view__status{background:var(--ck-color-base-error);color:var(--ck-color-base-background);padding:var(--ck-spacing-small) var(--ck-spacing-medium);min-width:var(--ck-table-properties-min-error-width);text-align:center;animation:0.15s both ck-table-form-labeled-view-status-appear}.ck.ck-special-characters>.ck-dialog__content>div>.ck-character-categories>.ck-labeled-field-view .ck.ck-labeled-field-view__status:after{border-color:transparent transparent var(--ck-color-base-error) transparent;border-width:0 var(--ck-table-properties-error-arrow-size) var(--ck-table-properties-error-arrow-size) var(--ck-table-properties-error-arrow-size);border-style:solid}@media (prefers-reduced-motion:reduce){.ck.ck-special-characters>.ck-dialog__content>div>.ck-character-categories>.ck-labeled-field-view .ck.ck-labeled-field-view__status{animation:none}}.ck.ck-special-characters>.ck-dialog__content>div>.ck-character-categories>.ck-labeled-field-view .ck-input.ck-error:not(:focus)+.ck.ck-labeled-field-view__status{display:none}.ck.ck-special-characters>.ck-dialog__content>div>.ck-character-categories>.ck-labeled-field-view>.ck-label{font-size:var(--ck-font-size-tiny);text-align:center}.ck.ck-special-characters>.ck-dialog__content>div>.ck-character-categories .ck-dropdown{width:100%;display:block}.ck.ck-special-characters>.ck-dialog__content>div>.ck-character-categories .ck-dropdown>button:not(:focus){border:1px solid var(--ck-color-base-border)}.ck.ck-special-characters>.ck-dialog__content>div>.ck-character-categories .ck-dropdown>button>span{width:100%}.ck.ck-special-characters>.ck-dialog__content>div>.ck-character-grid{grid-area:0.3333333333;max-height:200px}.ck.ck-special-characters>.ck-dialog__content>div>.ck-character-info{grid-area:0.375}:root{--ck-character-grid-tile-size: 24px}.ck.ck-character-grid{overflow:hidden auto}.ck.ck-character-grid .ck-character-grid__tiles{grid-template-columns:repeat(auto-fill, minmax(var(--ck-character-grid-tile-size), 1fr));margin:var(--ck-spacing-standard) var(--ck-spacing-large);grid-gap:var(--ck-spacing-standard);display:grid}.ck.ck-character-grid .ck-character-grid__tile{width:var(--ck-character-grid-tile-size);height:var(--ck-character-grid-tile-size);min-width:var(--ck-character-grid-tile-size);min-height:var(--ck-character-grid-tile-size);border:0;padding:0;font-size:1.5em;transition:box-shadow 0.2s}@media (prefers-reduced-motion:reduce){.ck.ck-character-grid .ck-character-grid__tile{transition:none}}.ck.ck-character-grid .ck-character-grid__tile:focus:not(.ck-disabled),.ck.ck-character-grid .ck-character-grid__tile:hover:not(.ck-disabled){box-shadow:inset 0 0 0 1px var(--ck-color-base-background), 0 0 0 2px var(--ck-color-focus-border);border:0}.ck.ck-character-grid .ck-character-grid__tile .ck-button__label{line-height:var(--ck-character-grid-tile-size);text-align:center;width:100%}.ck.ck-character-grid{max-width:100%}.ck.ck-character-info{padding:var(--ck-spacing-small) var(--ck-spacing-large);border-top:1px solid var(--ck-color-base-border);display:flex}.ck.ck-character-info>*{text-transform:uppercase;font-size:var(--ck-font-size-small)}.ck.ck-character-info .ck-character-info__name{text-overflow:ellipsis;max-width:280px;overflow:hidden}.ck.ck-character-info .ck-character-info__code{opacity:0.6}.ck.ck-character-info{justify-content:space-between}.ck.ck-dropdown.ck-style-dropdown.ck-style-dropdown_multiple-active>.ck-button>.ck-button__label{font-style:italic}:root{--ck-style-panel-button-width: 120px;--ck-style-panel-button-height: 80px;--ck-style-panel-button-label-background: #f0f0f0;--ck-style-panel-button-hover-label-background: #ebebeb;--ck-style-panel-button-hover-border-color: #b3b3b3;--ck-style-panel-columns: 3}.ck.ck-style-panel .ck-style-grid{row-gap:var(--ck-spacing-large);column-gap:var(--ck-spacing-large);grid-template-columns:repeat(var(--ck-style-panel-columns), auto);display:grid}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button{--ck-color-button-default-hover-background: var(--ck-color-base-background);--ck-color-button-default-active-background: var(--ck-color-base-background);width:var(--ck-style-panel-button-width);height:var(--ck-style-panel-button-height);justify-content:space-between;padding:0;display:flex}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button:not(:focus){border:1px solid var(--ck-color-base-border)}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button .ck-button__label{width:100%;height:22px;padding:0 var(--ck-spacing-medium);text-overflow:ellipsis;flex-shrink:0;line-height:22px;overflow:hidden}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button .ck-style-grid__button__preview{opacity:0.9;width:100%;padding:var(--ck-spacing-medium);background:var(--ck-color-base-background);border:2px solid var(--ck-color-base-background);flex-grow:1;flex-basis:100%;place-content:center flex-start;align-items:center;display:flex;overflow:hidden}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button.ck-disabled{--ck-color-button-default-disabled-background: var(--ck-color-base-foreground)}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button.ck-disabled:not(:focus){border-color:var(--ck-style-panel-button-label-background)}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button.ck-disabled .ck-style-grid__button__preview{opacity:0.4;border-color:var(--ck-color-base-foreground);filter:saturate(0.3)}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button.ck-on{border-color:var(--ck-color-base-active)}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button.ck-on .ck-button__label{box-shadow:0 -1px 0 var(--ck-color-base-active);z-index:1}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button.ck-on:hover{border-color:var(--ck-color-base-active-focus)}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button:not(.ck-on) .ck-button__label{background:var(--ck-style-panel-button-label-background)}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button:not(.ck-on):hover .ck-button__label{background:var(--ck-style-panel-button-hover-label-background)}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button:hover:not(.ck-disabled):not(.ck-on){border-color:var(--ck-style-panel-button-hover-border-color)}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button:hover:not(.ck-disabled):not(.ck-on) .ck-style-grid__button__preview{opacity:1}.ck.ck-style-panel .ck-style-grid .ck-style-grid__button{flex-direction:column}.ck.ck-style-panel .ck-style-grid{justify-content:start}.ck.ck-style-panel .ck-style-panel__style-group>.ck-label{margin:var(--ck-spacing-large) 0}.ck.ck-style-panel .ck-style-panel__style-group:first-child>.ck-label{margin-top:0}:root{--ck-style-panel-max-height: 470px}.ck.ck-style-panel{padding:var(--ck-spacing-large);max-height:var(--ck-style-panel-max-height);overflow-y:auto}.ck-content .table th,.ibo-is-html-content .table th{text-align:start}.ck-content[dir="rtl"] .table th,.ibo-is-html-content[dir="rtl"] .table th{text-align:right}.ck-content[dir="ltr"] .table th,.ibo-is-html-content[dir="ltr"] .table th{text-align:left}.ck-content figure.table:not(.layout-table),.ibo-is-html-content figure.table:not(.layout-table){display:table}.ck-content figure.table:not(.layout-table)>table,.ibo-is-html-content figure.table:not(.layout-table)>table{width:100%;height:100%}.ck-content .table:not(.layout-table),.ibo-is-html-content .table:not(.layout-table){margin:0.9em auto}.ck-content table.table:not(.layout-table),.ibo-is-html-content table.table:not(.layout-table),.ck-content figure.table:not(.layout-table)>table,.ibo-is-html-content figure.table:not(.layout-table)>table{border-collapse:collapse;border-spacing:0;border:1px double #b3b3b3}:is(:is(.ck-content table.table:not(.layout-table), .ck-content figure.table:not(.layout-table)>table)>thead, :is(.ck-content table.table:not(.layout-table), .ck-content figure.table:not(.layout-table)>table)>tfoot, :is(.ck-content table.table:not(.layout-table), .ck-content figure.table:not(.layout-table)>table)>tbody)>tr>th{background:#0000000d;font-weight:bold}:is(:is(:is(.ck-content table.table:not(.layout-table), .ck-content figure.table:not(.layout-table)>table)>thead, :is(.ck-content table.table:not(.layout-table), .ck-content figure.table:not(.layout-table)>table)>tfoot, :is(.ck-content table.table:not(.layout-table), .ck-content figure.table:not(.layout-table)>table)>tbody)>tr>td, :is(:is(.ck-content table.table:not(.layout-table), .ck-content figure.table:not(.layout-table)>table)>thead, :is(.ck-content table.table:not(.layout-table), .ck-content figure.table:not(.layout-table)>table)>tfoot, :is(.ck-content table.table:not(.layout-table), .ck-content figure.table:not(.layout-table)>table)>tbody)>tr>th)>p:first-of-type{margin-top:0}:is(:is(:is(.ck-content table.table:not(.layout-table), .ck-content figure.table:not(.layout-table)>table)>thead, :is(.ck-content table.table:not(.layout-table), .ck-content figure.table:not(.layout-table)>table)>tfoot, :is(.ck-content table.table:not(.layout-table), .ck-content figure.table:not(.layout-table)>table)>tbody)>tr>td, :is(:is(.ck-content table.table:not(.layout-table), .ck-content figure.table:not(.layout-table)>table)>thead, :is(.ck-content table.table:not(.layout-table), .ck-content figure.table:not(.layout-table)>table)>tfoot, :is(.ck-content table.table:not(.layout-table), .ck-content figure.table:not(.layout-table)>table)>tbody)>tr>th)>p:last-of-type{margin-bottom:0}:is(:is(.ck-content table.table:not(.layout-table), .ck-content figure.table:not(.layout-table)>table)>thead, :is(.ck-content table.table:not(.layout-table), .ck-content figure.table:not(.layout-table)>table)>tfoot, :is(.ck-content table.table:not(.layout-table), .ck-content figure.table:not(.layout-table)>table)>tbody)>tr>td,:is(:is(.ck-content table.table:not(.layout-table), .ck-content figure.table:not(.layout-table)>table)>thead, :is(.ck-content table.table:not(.layout-table), .ck-content figure.table:not(.layout-table)>table)>tfoot, :is(.ck-content table.table:not(.layout-table), .ck-content figure.table:not(.layout-table)>table)>tbody)>tr>th{border:1px solid #bfbfbf;min-width:2em;padding:0.4em}@media print{.ck-content figure.table:not(.layout-table),.ibo-is-html-content figure.table:not(.layout-table){width:fit-content;height:fit-content}.ck-content figure.table:not(.layout-table)>table,.ibo-is-html-content figure.table:not(.layout-table)>table{height:initial}}.ck-editor__editable .ck-table-bogus-paragraph{width:100%;display:inline-block}:root{--ck-color-table-focused-cell-background: #9ec9fa4d;--ck-table-content-default-border-color: #d4d4d4;--ck-table-border-none-helper-line-color: #d4d4d4;--ck-table-border-none-helper-line-style: dashed;--ck-table-border-none-helper-line-width: 1px}.ck-widget.table table[style*="border:none"],.ck-widget.table table[style*="border-style:none"],.ck-widget.table table[style*="border:0"],.ck-widget.table table[style*="border-width:0"]{outline:var(--ck-table-content-default-border-color) 1px dashed}:is(.ck-widget.table td, .ck-widget.table th).ck-editor__nested-editable{outline:unset}:is(.ck-widget.table td, .ck-widget.table th).ck-editor__nested-editable:not(.ck-editor__editable_selected).ck-editor__nested-editable_focused,:is(.ck-widget.table td, .ck-widget.table th).ck-editor__nested-editable:not(.ck-editor__editable_selected):focus{background:var(--ck-color-table-focused-cell-background);outline:1px solid var(--ck-color-focus-border);outline-offset:-1px}:where(.ck.ck-editor__editable.ck-table-show-hidden-borders .ck-widget.table){--ck-table-border-none-helper-line: var(--ck-table-border-none-helper-line-width) var(--ck-table-border-none-helper-line-style) - var(--ck-table-border-none-helper-line-color)}:where(.ck.ck-editor__editable.ck-table-show-hidden-borders .ck-widget.table) :where(td, th):where([style*="border:none"], [style*="border:0"], [style*="border-style:none"], [style*="border-width:0"]){border:var(--ck-table-border-none-helper-line) !important}:where(.ck.ck-editor__editable.ck-table-show-hidden-borders .ck-widget.table) :where(table, td, th):where([style*="border-top-style:none"], [style*="border-top-width:0"]){border-top:var(--ck-table-border-none-helper-line) !important}:where(.ck.ck-editor__editable.ck-table-show-hidden-borders .ck-widget.table) :where(table, td, th):where([style*="border-right-style:none"], [style*="border-right-width:0"]){border-right:var(--ck-table-border-none-helper-line) !important}:where(.ck.ck-editor__editable.ck-table-show-hidden-borders .ck-widget.table) :where(table, td, th):where([style*="border-bottom-style:none"], [style*="border-bottom-width:0"]){border-bottom:var(--ck-table-border-none-helper-line) !important}:where(.ck.ck-editor__editable.ck-table-show-hidden-borders .ck-widget.table) :where(table, td, th):where([style*="border-left-style:none"], [style*="border-left-width:0"]){border-left:var(--ck-table-border-none-helper-line) !important}.ck.ck-table-cell-properties-form{width:320px}.ck.ck-table-cell-properties-form .ck-form__row.ck-table-cell-properties-form__padding-row{align-self:flex-end;width:25%;padding:0}.ck.ck-table-cell-properties-form .ck-form__row.ck-table-cell-properties-form__alignment-row .ck.ck-toolbar{margin-top:var(--ck-spacing-standard);background:none}.ck.ck-table-cell-properties-form .ck-form__row.ck-table-cell-properties-form__alignment-row .ck.ck-toolbar.ck-table-cell-properties-form__horizontal-alignment-toolbar{--ck-table-form-dimensions-input-width: calc(var(--ck-table-form-default-input-width) * 2 + var(--ck-spacing-large));width:var(--ck-table-form-dimensions-input-width);max-width:var(--ck-table-form-dimensions-input-width);min-width:var(--ck-table-form-dimensions-input-width);padding:0}.ck.ck-table-cell-properties-form .ck-form__row.ck-table-cell-properties-form__alignment-row .ck.ck-toolbar.ck-table-cell-properties-form__vertical-alignment-toolbar{flex-grow:1}.ck.ck-table-cell-properties-form .ck-form__row.ck-table-cell-properties-form__alignment-row .ck.ck-toolbar:first-of-type{flex-grow:0.57}.ck.ck-table-cell-properties-form .ck-form__row.ck-table-cell-properties-form__alignment-row .ck.ck-toolbar:last-of-type{flex-grow:0.43}.ck.ck-table-cell-properties-form .ck-form__row.ck-table-cell-properties-form__alignment-row .ck.ck-toolbar .ck-button{flex-grow:1}.ck.ck-table-cell-properties-form .ck-form__row.ck-table-cell-properties-form__alignment-row{flex-wrap:wrap}.ck.ck-table-cell-properties-form .ck-form__row.ck-table-form__border-row .ck-labeled-field-view>.ck-label{font-size:var(--ck-font-size-tiny);text-align:center}.ck.ck-table-cell-properties-form .ck-form__row.ck-table-form__border-row .ck-table-form__border-style,.ck.ck-table-cell-properties-form .ck-form__row.ck-table-form__border-row .ck-table-form__border-width{width:80px;min-width:80px;max-width:80px}.ck.ck-table-cell-properties-form .ck-form__row.ck-table-form__dimensions-row{--ck-table-form-dimensions-input-width: calc(var(--ck-table-form-default-input-width) * 2 + var(--ck-spacing-large));width:var(--ck-table-form-dimensions-input-width);max-width:var(--ck-table-form-dimensions-input-width);min-width:var(--ck-table-form-dimensions-input-width);padding:0}.ck.ck-table-cell-properties-form .ck-form__row.ck-table-form__dimensions-row .ck-table-form__dimensions-row__width,.ck.ck-table-cell-properties-form .ck-form__row.ck-table-form__dimensions-row .ck-table-form__dimensions-row__height{width:var(--ck-table-form-default-input-width);min-width:var(--ck-table-form-default-input-width);max-width:var(--ck-table-form-default-input-width);margin:0}.ck.ck-table-cell-properties-form .ck-form__row.ck-table-form__dimensions-row .ck-table-form__dimension-operator{width:0;height:var(--ck-ui-component-min-height);line-height:var(--ck-ui-component-min-height);margin:0 var(--ck-spacing-small);align-self:flex-end;display:inline-block;position:relative;left:-0.5ch;overflow:visible}.ck.ck-table-cell-properties-form .ck-form__row.ck-form__row.ck-table-form__action-row>.ck.ck-button{flex-grow:initial}.ck.ck-table-cell-properties-form .ck-form__row.ck-form__row.ck-table-form__action-row>.ck.ck-button .ck-button__label{color:currentColor}.ck.ck-table-cell-properties-form .ck-form__row.ck-table-form__cell-type-row{--ck-table-form-dimensions-input-width: calc(var(--ck-table-form-default-input-width) * 2 + var(--ck-spacing-large));width:var(--ck-table-form-dimensions-input-width);max-width:var(--ck-table-form-dimensions-input-width);min-width:var(--ck-table-form-dimensions-input-width);padding:0}:root{--ck-table-layout-widget-type-around-button-size: 16px;--ck-table-layout-widget-type-around-icon-width: 10px;--ck-table-layout-widget-type-around-icon-height: 8px;--ck-table-layout-widget-handler-icon-size: 10px;--ck-table-layout-default-border-color: #d4d4d4}.ck-content table.table.layout-table,.ibo-is-html-content table.table.layout-table,.ck-content figure.table.layout-table,.ibo-is-html-content figure.table.layout-table{margin-top:0;margin-bottom:0}.ck-content table.table.layout-table,.ibo-is-html-content table.table.layout-table,.ck-content figure.table.layout-table>table,.ibo-is-html-content figure.table.layout-table>table{border-spacing:0}.ck-editor__editable .table.layout-table>table{border-collapse:revert;width:100%;height:100%}.ck-editor__editable .table.layout-table>table:not([style*="border:"], [style*="border-top"], [style*="border-bottom"], [style*="border-left"], [style*="border-right"], [style*="border-width"], [style*="border-style"], [style*="border-color"]){border-width:0;border-color:#0000;outline:none}.ck-editor__editable .table.layout-table>table>tbody>tr>td{box-shadow:revert;padding:revert;text-indent:1px;border-color:var(--ck-table-layout-default-border-color);border-style:dashed;min-width:2em}.ck-editor__editable .table.layout-table>table>tbody>tr>td[style^="width:"],.ck-editor__editable .table.layout-table>table>tbody>tr>td[style*=" width:"],.ck-editor__editable .table.layout-table>table>tbody>tr>td[style*=";width:"]{min-width:auto}.ck-editor__editable .table.layout-table>table>tbody>tr>td:focus{background-color:#0000}.ck-editor__editable .table.layout-table>table>tbody>tr>td:not([style*="border:"], [style*="border-top"], [style*="border-bottom"], [style*="border-left"], [style*="border-right"], [style*="border-width"], [style*="border-style"], [style*="border-color"]){outline:var(--ck-table-layout-default-border-color) 1px dashed;outline-offset:-1px;border-width:0;border-color:#0000}.ck-editor__editable .table.layout-table>table>tbody>tr>td:not([style*="border:"], [style*="border-top"], [style*="border-bottom"], [style*="border-left"], [style*="border-right"], [style*="border-width"], [style*="border-style"], [style*="border-color"]):focus{outline:var(--ck-color-focus-border) 1px solid}.ck-editor__editable .table.layout-table>table>tbody>tr>td>.ck-table-bogus-paragraph{text-indent:0;width:calc(100% - 1px)}.ck-editor__editable .table.layout-table.ck-widget>.ck-widget__type-around{--ck-widget-type-around-button-size: var(--ck-table-layout-widget-type-around-button-size)}.ck-editor__editable .table.layout-table.ck-widget>.ck-widget__type-around>.ck-widget__type-around__button.ck-widget__type-around__button_before,.ck-editor__editable .table.layout-table.ck-widget>.ck-widget__type-around>.ck-widget__type-around__button.ck-widget__type-around__button_after{z-index:2;transform:translateY(0)}.ck-editor__editable .table.layout-table.ck-widget>.ck-widget__type-around>.ck-widget__type-around__button.ck-widget__type-around__button_before{margin-left:var(--ck-table-layout-widget-type-around-button-size);border-radius:0 0 100px 100px;left:min(10%, 30px)}.ck-editor__editable .table.layout-table.ck-widget>.ck-widget__type-around>.ck-widget__type-around__button.ck-widget__type-around__button_before:after{border-radius:0 0 100px 100px}.ck-editor__editable .table.layout-table.ck-widget>.ck-widget__type-around>.ck-widget__type-around__button.ck-widget__type-around__button_after{border-radius:100px 100px 0 0}.ck-editor__editable .table.layout-table.ck-widget>.ck-widget__type-around>.ck-widget__type-around__button.ck-widget__type-around__button_after:after{border-radius:100px 100px 0 0}.ck-editor__editable .table.layout-table.ck-widget>.ck-widget__type-around>.ck-widget__type-around__button svg{width:var(--ck-table-layout-widget-type-around-icon-width);height:var(--ck-table-layout-widget-type-around-icon-height)}.ck-editor__editable .table.layout-table.ck-widget.ck-widget_with-selection-handle>.ck-widget__selection-handle{--ck-widget-handler-icon-size: var(--ck-table-layout-widget-handler-icon-size);transform:translateY(calc(0px - var(--ck-widget-outline-thickness)));z-index:3}.ck-editor__editable .table.layout-table.ck-widget.ck-widget_type-around_show-fake-caret_before>.ck-widget__type-around>.ck-widget__type-around__fake-caret{top:0}.ck-editor__editable .table.layout-table.ck-widget.ck-widget_type-around_show-fake-caret_after>.ck-widget__type-around>.ck-widget__type-around__fake-caret{bottom:0}.ck-editor__editable .table.layout-table.ck-widget:hover{z-index:var(--ck-z-default)}.ck-editor__editable .table.layout-table.ck-widget:hover>.ck-widget__selection-handle{opacity:0.75;visibility:visible}.ck-editor__editable .table.layout-table.ck-widget:hover>.ck-widget__selection-handle:hover{opacity:1}.ck-editor__editable .table.layout-table.ck-widget:has(.ck-widget.table:hover)>.ck-widget__selection-handle{opacity:0;visibility:hidden}.ck-editor__editable .table.layout-table.ck-widget.ck-widget_selected{z-index:var(--ck-z-default)}.ck-editor__editable .table.layout-table{margin:0;display:table}.ck-editor__editable.ck-editor__editable_inline>.ck-widget.ck-widget_with-selection-handle.layout-table:first-child{margin-top:var(--ck-spacing-large)}.ck-editor__editable.ck-editor__editable_inline>.ck-widget.ck-widget_with-selection-handle.layout-table:last-child,.ck-editor__editable.ck-editor__editable_inline>.ck-widget.ck-widget_with-selection-handle.layout-table:nth-last-child(2):has(+ .ck-fake-selection-container){margin-bottom:var(--ck-spacing-large)}.ck.ck-form__row>:not(.ck-label)+*{margin-inline-start:var(--ck-spacing-large)}.ck.ck-form__row>.ck-label{width:100%;min-width:100%}.ck.ck-form__row.ck-table-form__action-row{margin-top:var(--ck-spacing-large);justify-content:flex-end}.ck.ck-form__row.ck-table-form__action-row .ck-button-save,.ck.ck-form__row.ck-table-form__action-row .ck-button-cancel{justify-content:center}:root{--ck-table-properties-error-arrow-size: 6px;--ck-table-properties-min-error-width: 150px}.ck.ck-table-form{--ck-table-form-default-input-width: 80px}.ck.ck-table-form .ck-form__row.ck-table-form__border-row .ck-labeled-field-view>.ck-label{font-size:var(--ck-font-size-tiny);text-align:center}.ck.ck-table-form .ck-form__row.ck-table-form__border-row .ck-table-form__border-style,.ck.ck-table-form .ck-form__row.ck-table-form__border-row .ck-table-form__border-width{width:var(--ck-table-form-default-input-width);min-width:var(--ck-table-form-default-input-width);max-width:var(--ck-table-form-default-input-width)}.ck.ck-table-form .ck-form__row.ck-table-form__dimensions-row{--ck-table-form-dimensions-input-width: calc(var(--ck-table-form-default-input-width) * 2 + var(--ck-spacing-large));width:var(--ck-table-form-dimensions-input-width);max-width:var(--ck-table-form-dimensions-input-width);min-width:var(--ck-table-form-dimensions-input-width);padding:0}.ck.ck-table-form .ck-form__row.ck-table-form__dimensions-row .ck-table-form__dimensions-row__width,.ck.ck-table-form .ck-form__row.ck-table-form__dimensions-row .ck-table-form__dimensions-row__height{width:var(--ck-table-form-default-input-width);min-width:var(--ck-table-form-default-input-width);max-width:var(--ck-table-form-default-input-width);margin:0}.ck.ck-table-form .ck-form__row.ck-table-form__dimensions-row .ck-table-form__dimension-operator{width:0;height:var(--ck-ui-component-min-height);line-height:var(--ck-ui-component-min-height);margin:0 var(--ck-spacing-small);align-self:flex-end;display:inline-block;position:relative;left:-0.5ch;overflow:visible}.ck.ck-table-form .ck-form__row.ck-table-form__border-row,.ck.ck-table-form .ck-form__row.ck-table-form__background-row,.ck.ck-table-form .ck-form__row.ck-table-form__cell-type-row{flex-wrap:wrap}.ck.ck-table-form .ck-form__row.ck-table-form__dimensions-row,.ck.ck-table-form .ck-form__row.ck-table-form__cell-type-row{flex-wrap:wrap;align-items:center}:is(.ck.ck-table-form .ck-form__row.ck-table-form__dimensions-row, .ck.ck-table-form .ck-form__row.ck-table-form__cell-type-row) .ck-labeled-field-view{flex-direction:column-reverse;align-items:center;display:flex}:is(.ck.ck-table-form .ck-form__row.ck-table-form__dimensions-row, .ck.ck-table-form .ck-form__row.ck-table-form__cell-type-row) .ck-labeled-field-view .ck.ck-dropdown{flex-grow:0}.ck.ck-table-form .ck-form__row:not(.ck-table-form__action-row)>:not(.ck-label, .ck-table-form__dimension-operator){flex-grow:1}.ck.ck-table-form .ck.ck-labeled-field-view{padding-top:var(--ck-spacing-standard)}.ck.ck-table-form .ck.ck-labeled-field-view .ck.ck-labeled-field-view__status{border-radius:var(--ck-rounded-corners-radius);background:var(--ck-color-base-error);color:var(--ck-color-base-background);padding:var(--ck-spacing-small) var(--ck-spacing-medium);min-width:var(--ck-table-properties-min-error-width);text-align:center;left:50%;bottom:calc(-1 * var(--ck-table-properties-error-arrow-size));animation:0.15s both ck-table-form-labeled-view-status-appear;position:absolute;transform:translate(-50%, 100%)}.ck.ck-table-form .ck.ck-labeled-field-view .ck.ck-labeled-field-view__status:after{border-color:transparent transparent var(--ck-color-base-error) transparent;border-width:0 var(--ck-table-properties-error-arrow-size) var(--ck-table-properties-error-arrow-size) var(--ck-table-properties-error-arrow-size);content:"";top:calc(-1 * var(--ck-table-properties-error-arrow-size));border-style:solid;position:absolute;left:50%;transform:translateX(-50%)}@media (prefers-reduced-motion:reduce){.ck.ck-table-form .ck.ck-labeled-field-view .ck.ck-labeled-field-view__status{animation:none}}.ck.ck-table-form .ck.ck-labeled-field-view .ck.ck-labeled-field-view__status{z-index:1}.ck.ck-table-form .ck.ck-labeled-field-view .ck-input.ck-error:not(:focus)+.ck.ck-labeled-field-view__status{display:none}.ck.ck-table-form .ck.ck-labeled-field-view{position:relative}@keyframes ck-table-form-labeled-view-status-appear{0%{opacity:0}100%{opacity:1}}.ck.ck-table-properties-form{width:320px}.ck.ck-table-properties-form .ck-form__row.ck-table-properties-form__alignment-row{flex-wrap:wrap;flex-basis:0;align-content:baseline;align-self:flex-end}.ck.ck-table-properties-form .ck-form__row.ck-table-properties-form__alignment-row .ck.ck-toolbar{margin-top:var(--ck-spacing-standard);background:none}.ck.ck-table-properties-form .ck-form__row.ck-table-properties-form__alignment-row .ck.ck-toolbar .ck-toolbar__items>*{flex:1}.ck.ck-table-properties-form .ck-form__row.ck-table-properties-form__alignment-row .ck.ck-toolbar .ck-toolbar__items{flex-wrap:nowrap}:root{--ck-content-table-style-spacing: 1.5em}.ck-content .table.table-style-align-left,.ibo-is-html-content .table.table-style-align-left{float:left;margin-right:var(--ck-content-table-style-spacing)}.ck-content .table.table-style-align-right,.ibo-is-html-content .table.table-style-align-right{float:right;margin-left:var(--ck-content-table-style-spacing)}.ck-content .table.table-style-align-center,.ibo-is-html-content .table.table-style-align-center{margin-left:auto;margin-right:auto}.ck-content .table.table-style-block-align-left,.ibo-is-html-content .table.table-style-block-align-left{margin-left:0;margin-right:auto}.ck-content .table.table-style-block-align-right,.ibo-is-html-content .table.table-style-block-align-right{margin-left:auto;margin-right:0}.ck-editor__editable .table.layout-table.table-style-align-center{margin-left:auto;margin-right:auto}.ck-editor__editable .table.layout-table.table-style-align-left{margin-right:var(--ck-content-table-style-spacing)}.ck-editor__editable .table.layout-table.table-style-align-right{margin-left:var(--ck-content-table-style-spacing)}.ck-editor__editable .table.layout-table.table-style-block-align-left{margin-left:0;margin-right:auto}.ck-editor__editable .table.layout-table.table-style-block-align-right{margin-left:auto;margin-right:0}:root{--ck-content-color-table-caption-background: #f7f7f7;--ck-content-color-table-caption-text: #333;--ck-color-table-caption-highlighted-background: #fd0}.ck-content .table>figcaption,.ibo-is-html-content .table>figcaption,.ck-content figure.table>table>caption,.ibo-is-html-content figure.table>table>caption{caption-side:top;word-break:normal;overflow-wrap:anywhere;text-align:center;color:var(--ck-content-color-table-caption-text);background-color:var(--ck-content-color-table-caption-background);outline-offset:-1px;padding:0.6em;font-size:0.75em;display:table-caption}@media (forced-colors:active){.ck-content .table>figcaption,.ibo-is-html-content .table>figcaption,.ck-content figure.table>table>caption,.ibo-is-html-content figure.table>table>caption{background-color:unset;color:unset}}@media (forced-colors:none){:is(.ck.ck-editor__editable .table>figcaption, .ck.ck-editor__editable figure.table>table>caption).table__caption_highlighted{animation:0.6s ease-out ck-table-caption-highlight}}:is(.ck.ck-editor__editable .table>figcaption, .ck.ck-editor__editable figure.table>table>caption).ck-placeholder:before{padding-left:inherit;padding-right:inherit;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}@keyframes ck-table-caption-highlight{0%{background-color:var(--ck-color-table-caption-highlighted-background)}100%{background-color:var(--ck-content-color-table-caption-background)}}:root{--ck-table-selected-cell-background: #9ecffa4d}.ck.ck-editor__editable .table table td.ck-editor__editable_selected,.ck.ck-editor__editable .table table th.ck-editor__editable_selected{caret-color:#0000;box-shadow:unset;position:relative}:is(.ck.ck-editor__editable .table table td.ck-editor__editable_selected, .ck.ck-editor__editable .table table th.ck-editor__editable_selected):after{content:"";pointer-events:none;background-color:var(--ck-table-selected-cell-background);position:absolute;inset:0}:is(.ck.ck-editor__editable .table table td.ck-editor__editable_selected, .ck.ck-editor__editable .table table th.ck-editor__editable_selected) ::selection,:is(.ck.ck-editor__editable .table table td.ck-editor__editable_selected, .ck.ck-editor__editable .table table th.ck-editor__editable_selected):focus{background-color:#0000}:is(.ck.ck-editor__editable .table table td.ck-editor__editable_selected, .ck.ck-editor__editable .table table th.ck-editor__editable_selected) .ck-widget{outline:unset}:is(.ck.ck-editor__editable .table table td.ck-editor__editable_selected, .ck.ck-editor__editable .table table th.ck-editor__editable_selected) .ck-widget>.ck-widget__selection-handle{display:none}:root{--ck-color-table-column-resizer-hover: var(--ck-color-base-active);--ck-table-column-resizer-width: 7px;--ck-table-column-resizer-position-offset: calc(var(--ck-table-column-resizer-width) * -.5 - .5px)}.ck-content .table .ck-table-resized,.ibo-is-html-content .table .ck-table-resized{table-layout:fixed}.ck-content .table td,.ibo-is-html-content .table td,.ck-content .table th,.ibo-is-html-content .table th{overflow-wrap:break-word}.ck.ck-editor__editable .table td,.ck.ck-editor__editable .table th{position:relative}.ck.ck-editor__editable .table .ck-table-column-resizer{top:0;bottom:0;right:var(--ck-table-column-resizer-position-offset);width:var(--ck-table-column-resizer-width);cursor:col-resize;user-select:none;z-index:var(--ck-z-default);position:absolute}.ck.ck-editor__editable.ck-column-resize_disabled .table .ck-table-column-resizer,.ck.ck-editor__editable .table[draggable] .ck-table-column-resizer{display:none}.ck.ck-editor__editable .table .ck-table-column-resizer:hover,.ck.ck-editor__editable .table .ck-table-column-resizer__active{background-color:var(--ck-color-table-column-resizer-hover);opacity:0.25}.ck.ck-editor__editable[dir="rtl"] .table .ck-table-column-resizer{left:var(--ck-table-column-resizer-position-offset);right:unset}[dir="ltr"] :is(.ck.ck-input-color>.ck.ck-input-text){border-top-right-radius:0;border-bottom-right-radius:0}[dir="rtl"] :is(.ck.ck-input-color>.ck.ck-input-text){border-top-left-radius:0;border-bottom-left-radius:0}.ck.ck-input-color>.ck.ck-input-text:focus{z-index:0}.ck.ck-input-color>.ck.ck-dropdown>.ck.ck-button.ck-input-color__button{padding:0;display:flex}[dir="ltr"] :is(.ck.ck-input-color>.ck.ck-dropdown>.ck.ck-button.ck-input-color__button){border-top-left-radius:0;border-bottom-left-radius:0}[dir="ltr"] :is(.ck.ck-input-color>.ck.ck-dropdown>.ck.ck-button.ck-input-color__button):not(:focus){border-left:1px solid #0000}[dir="rtl"] :is(.ck.ck-input-color>.ck.ck-dropdown>.ck.ck-button.ck-input-color__button){border-top-right-radius:0;border-bottom-right-radius:0}[dir="rtl"] :is(.ck.ck-input-color>.ck.ck-dropdown>.ck.ck-button.ck-input-color__button):not(:focus){border-right:1px solid #0000}.ck.ck-input-color>.ck.ck-dropdown>.ck.ck-button.ck-input-color__button.ck-disabled{background:var(--ck-color-input-disabled-background)}.ck.ck-input-color>.ck.ck-dropdown>.ck.ck-button.ck-input-color__button>.ck.ck-input-color__button__preview{border-radius:var(--ck-rounded-corners-radius);border:1px solid var(--ck-color-input-border);width:20px;height:20px;position:relative;overflow:hidden}.ck.ck-input-color>.ck.ck-dropdown>.ck.ck-button.ck-input-color__button>.ck.ck-input-color__button__preview>.ck.ck-input-color__button__preview__no-color-indicator{transform-origin:50%;background:red;border-radius:2px;width:8%;height:150%;display:block;position:absolute;top:-30%;left:50%;transform:rotate(45deg)}.ck.ck-input-color .ck.ck-input-color__remove-color{width:100%;padding:calc(var(--ck-spacing-standard) / 2) var(--ck-spacing-standard);border-bottom-right-radius:0;border-bottom-left-radius:0}.ck.ck-input-color .ck.ck-input-color__remove-color:not(:focus){border-bottom:1px solid var(--ck-color-input-border)}[dir="ltr"] :is(.ck.ck-input-color .ck.ck-input-color__remove-color){border-top-right-radius:0}[dir="rtl"] :is(.ck.ck-input-color .ck.ck-input-color__remove-color){border-top-left-radius:0}.ck.ck-input-color .ck.ck-input-color__remove-color .ck.ck-icon{margin-right:var(--ck-spacing-standard)}[dir="rtl"] :is(.ck.ck-input-color .ck.ck-input-color__remove-color .ck.ck-icon){margin-right:0;margin-left:var(--ck-spacing-standard)}.ck.ck-input-color{flex-direction:row-reverse;width:100%;display:flex}.ck.ck-input-color>input.ck.ck-input-text{flex-grow:1;min-width:auto}.ck.ck-input-color>div.ck.ck-dropdown{min-width:auto}.ck.ck-input-color>div.ck.ck-dropdown>.ck-input-color__button .ck-dropdown__arrow{display:none}:root{--ck-insert-table-dropdown-padding: 10px;--ck-insert-table-dropdown-box-height: 11px;--ck-insert-table-dropdown-box-width: 12px;--ck-insert-table-dropdown-box-margin: 1px}.ck .ck-insert-table-dropdown__grid{width:calc(var(--ck-insert-table-dropdown-box-width) * 10 + var(--ck-insert-table-dropdown-box-margin) * 20 + var(--ck-insert-table-dropdown-padding) * 2);padding:var(--ck-insert-table-dropdown-padding) var(--ck-insert-table-dropdown-padding) 0;flex-flow:wrap;display:flex}.ck .ck-insert-table-dropdown__label,.ck[dir="rtl"] .ck-insert-table-dropdown__label{text-align:center}.ck .ck-insert-table-dropdown-grid-box{min-width:var(--ck-insert-table-dropdown-box-width);min-height:var(--ck-insert-table-dropdown-box-height);margin:var(--ck-insert-table-dropdown-box-margin);border:1px solid var(--ck-color-base-border);border-radius:1px;outline:none;transition:none}@media (prefers-reduced-motion:reduce){.ck .ck-insert-table-dropdown-grid-box{transition:none}}.ck .ck-insert-table-dropdown-grid-box:focus{box-shadow:none}.ck .ck-insert-table-dropdown-grid-box.ck-on{border-color:var(--ck-color-focus-border);background:var(--ck-color-focus-outer-shadow)}:root{--ck-widget-outline-thickness: 3px;--ck-widget-handler-icon-size: 16px;--ck-widget-handler-animation-duration: .2s;--ck-widget-handler-animation-curve: ease;--ck-color-widget-blurred-border: #dedede;--ck-color-widget-hover-border: #ffc83d;--ck-color-widget-editable-focus-background: var(--ck-color-base-background);--ck-color-widget-drag-handler-icon-color: var(--ck-color-base-background);--ck-color-resizer: var(--ck-color-focus-border);--ck-color-resizer-tooltip-background: #262626;--ck-color-resizer-tooltip-text: #f2f2f2;--ck-resizer-border-radius: var(--ck-border-radius);--ck-resizer-tooltip-offset: 10px;--ck-resizer-tooltip-height: calc(var(--ck-spacing-small) * 2 + 10px)}.ck .ck-widget{outline-width:var(--ck-widget-outline-thickness);transition:outline-color var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve);outline-style:solid;outline-color:#0000}@media (prefers-reduced-motion:reduce){.ck .ck-widget{transition:none}}.ck .ck-widget.ck-widget_selected,.ck .ck-widget.ck-widget_selected:hover{outline:var(--ck-widget-outline-thickness) solid var(--ck-color-focus-border)}.ck .ck-widget:hover{outline-color:var(--ck-color-widget-hover-border)}.ck .ck-widget{position:relative}.ck .ck-editor__nested-editable{border:1px solid #0000}.ck .ck-editor__nested-editable.ck-editor__nested-editable_focused,.ck .ck-editor__nested-editable:focus{box-shadow:var(--ck-inner-shadow), 0 0}@media (forced-colors:none){.ck .ck-editor__nested-editable.ck-editor__nested-editable_focused,.ck .ck-editor__nested-editable:focus{background-color:var(--ck-color-widget-editable-focus-background)}}:is(.ck .ck-editor__nested-editable.ck-editor__nested-editable_focused, .ck .ck-editor__nested-editable:focus):not(td, th){border:var(--ck-focus-ring);outline:none}.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle{box-sizing:border-box;opacity:0;transition:background-color var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve), visibility var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve), opacity var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve);border-radius:var(--ck-border-radius) var(--ck-border-radius) 0 0;left:calc(0px - var(--ck-widget-outline-thickness));background-color:#0000;padding:4px;top:0;transform:translateY(-100%)}@media (prefers-reduced-motion:reduce){.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle{transition:none}}.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle .ck-icon{width:var(--ck-widget-handler-icon-size);height:var(--ck-widget-handler-icon-size);color:var(--ck-color-widget-drag-handler-icon-color)}.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle .ck-icon .ck-icon__selected-indicator{opacity:0;transition:opacity 0.3s var(--ck-widget-handler-animation-curve)}@media (prefers-reduced-motion:reduce){.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle .ck-icon .ck-icon__selected-indicator{transition:none}}.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle .ck-icon{display:block}.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle:hover .ck-icon .ck-icon__selected-indicator{opacity:1}.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle{position:absolute}.ck .ck-widget.ck-widget_with-selection-handle:hover>.ck-widget__selection-handle{opacity:1;background-color:var(--ck-color-widget-hover-border);visibility:visible}:is(.ck .ck-widget.ck-widget_with-selection-handle.ck-widget_selected, .ck .ck-widget.ck-widget_with-selection-handle.ck-widget_selected:hover)>.ck-widget__selection-handle{opacity:1;background-color:var(--ck-color-focus-border);visibility:visible}:is(.ck .ck-widget.ck-widget_with-selection-handle.ck-widget_selected, .ck .ck-widget.ck-widget_with-selection-handle.ck-widget_selected:hover)>.ck-widget__selection-handle .ck-icon .ck-icon__selected-indicator{opacity:1}.ck .ck-widget.ck-widget_with-selection-handle{position:relative}.ck[dir="rtl"] .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle{left:auto;right:calc(0px - var(--ck-widget-outline-thickness))}.ck.ck-editor__editable.ck-read-only .ck-widget{transition:none}.ck.ck-editor__editable.ck-read-only .ck-widget:not(.ck-widget_selected){--ck-widget-outline-thickness: 0px}.ck.ck-editor__editable.ck-read-only .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle,.ck.ck-editor__editable.ck-read-only .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle:hover{background:var(--ck-color-widget-blurred-border)}.ck .ck-widget:has(.ck-widget.table:hover){outline-color:#0000}.ck .ck-widget.ck-widget_with-selection-handle:has(.ck-widget.table:hover)>.ck-widget__selection-handle{opacity:0;visibility:hidden}.ck.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected,.ck.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected:hover{outline-color:var(--ck-color-widget-blurred-border)}:is(.ck.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected, .ck.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected:hover).ck-widget_with-selection-handle>.ck-widget__selection-handle,:is(.ck.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected, .ck.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected:hover).ck-widget_with-selection-handle>.ck-widget__selection-handle:hover{background:var(--ck-color-widget-blurred-border)}.ck.ck-editor__editable:not(.ck-pagination-view)>.ck-widget.ck-widget_with-selection-handle:first-child,.ck.ck-editor__editable:not(.ck-pagination-view) blockquote>.ck-widget.ck-widget_with-selection-handle:first-child{margin-top:calc(1em + var(--ck-widget-handler-icon-size))}.ck .ck-size-view{background:var(--ck-color-resizer-tooltip-background);color:var(--ck-color-resizer-tooltip-text);border:1px solid var(--ck-color-resizer-tooltip-text);border-radius:var(--ck-resizer-border-radius);font-size:var(--ck-font-size-tiny);padding:0 var(--ck-spacing-small);height:var(--ck-resizer-tooltip-height);line-height:var(--ck-resizer-tooltip-height);display:block}.ck .ck-size-view.ck-orientation-top-left,.ck .ck-size-view.ck-orientation-top-right,.ck .ck-size-view.ck-orientation-bottom-right,.ck .ck-size-view.ck-orientation-bottom-left,.ck .ck-size-view.ck-orientation-above-center{position:absolute}.ck .ck-size-view.ck-orientation-top-left{top:var(--ck-resizer-tooltip-offset);left:var(--ck-resizer-tooltip-offset)}.ck .ck-size-view.ck-orientation-top-right{top:var(--ck-resizer-tooltip-offset);right:var(--ck-resizer-tooltip-offset)}.ck .ck-size-view.ck-orientation-bottom-right{bottom:var(--ck-resizer-tooltip-offset);right:var(--ck-resizer-tooltip-offset)}.ck .ck-size-view.ck-orientation-bottom-left{bottom:var(--ck-resizer-tooltip-offset);left:var(--ck-resizer-tooltip-offset)}.ck .ck-size-view.ck-orientation-above-center{top:calc(var(--ck-resizer-tooltip-height) * -1);left:50%;transform:translate(-50%)}:root{--ck-resizer-size: 10px;--ck-resizer-offset: calc(( var(--ck-resizer-size) / -2 ) - 2px);--ck-resizer-border-width: 1px}.ck .ck-widget__resizer{outline:1px solid var(--ck-color-resizer);pointer-events:none;display:none;position:absolute;top:0;left:0}.ck .ck-widget__resizer__handle{width:var(--ck-resizer-size);height:var(--ck-resizer-size);background:var(--ck-color-focus-border);border:var(--ck-resizer-border-width) solid #fff;border-radius:var(--ck-resizer-border-radius);pointer-events:all;position:absolute}.ck .ck-widget__resizer__handle.ck-widget__resizer__handle-top-left{top:var(--ck-resizer-offset);left:var(--ck-resizer-offset)}.ck .ck-widget__resizer__handle.ck-widget__resizer__handle-top-right{top:var(--ck-resizer-offset);right:var(--ck-resizer-offset)}.ck .ck-widget__resizer__handle.ck-widget__resizer__handle-bottom-right{bottom:var(--ck-resizer-offset);right:var(--ck-resizer-offset)}.ck .ck-widget__resizer__handle.ck-widget__resizer__handle-bottom-left{bottom:var(--ck-resizer-offset);left:var(--ck-resizer-offset)}.ck .ck-widget__resizer__handle.ck-widget__resizer__handle-top-left,.ck .ck-widget__resizer__handle.ck-widget__resizer__handle-bottom-right{cursor:nwse-resize}.ck .ck-widget__resizer__handle.ck-widget__resizer__handle-top-right,.ck .ck-widget__resizer__handle.ck-widget__resizer__handle-bottom-left{cursor:nesw-resize}.ck .ck-widget_with-resizer{position:relative}.ck-focused .ck-widget_with-resizer.ck-widget_selected>.ck-widget__resizer{display:block}:root{--ck-widget-type-around-button-size: 20px;--ck-color-widget-type-around-button-active: var(--ck-color-focus-border);--ck-color-widget-type-around-button-hover: var(--ck-color-widget-hover-border);--ck-color-widget-type-around-button-blurred-editable: var(--ck-color-widget-blurred-border);--ck-color-widget-type-around-button-radar-start-alpha: 0;--ck-color-widget-type-around-button-radar-end-alpha: .3;--ck-color-widget-type-around-button-icon: var(--ck-color-base-background)}.ck .ck-widget .ck-widget__type-around__button{width:var(--ck-widget-type-around-button-size);height:var(--ck-widget-type-around-button-size);background:var(--ck-color-widget-type-around-button);transition:opacity var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve), background var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve);opacity:0;pointer-events:none;z-index:var(--ck-z-default);border-radius:100px;display:block;position:absolute;overflow:hidden}@media (prefers-reduced-motion:reduce){.ck .ck-widget .ck-widget__type-around__button{transition:none}}.ck .ck-widget .ck-widget__type-around__button svg{width:10px;height:8px;margin-top:1px;transition:transform 0.5s;position:absolute;top:50%;left:50%;transform:translate(-50%, -50%)}@media (prefers-reduced-motion:reduce){.ck .ck-widget .ck-widget__type-around__button svg{transition:none}}.ck .ck-widget .ck-widget__type-around__button svg *{stroke-dasharray:10;stroke-dashoffset:0;fill:none;stroke:var(--ck-color-widget-type-around-button-icon);stroke-width:1.5px;stroke-linecap:round;stroke-linejoin:round}.ck .ck-widget .ck-widget__type-around__button svg line{stroke-dasharray:7}.ck .ck-widget .ck-widget__type-around__button svg{z-index:calc(var(--ck-z-default) + 2)}.ck .ck-widget .ck-widget__type-around__button:hover{animation:1s infinite ck-widget-type-around-button-sonar}.ck .ck-widget .ck-widget__type-around__button:hover svg polyline{animation:2s linear ck-widget-type-around-arrow-dash}.ck .ck-widget .ck-widget__type-around__button:hover svg line{animation:2s linear ck-widget-type-around-arrow-tip-dash}@media (prefers-reduced-motion:reduce){.ck .ck-widget .ck-widget__type-around__button:hover{animation:none}.ck .ck-widget .ck-widget__type-around__button:hover svg polyline,.ck .ck-widget .ck-widget__type-around__button:hover svg line{animation:none}}.ck .ck-widget .ck-widget__type-around__button.ck-widget__type-around__button_before{top:calc(-.5 * var(--ck-widget-outline-thickness));left:min(10%, 30px);transform:translateY(-50%)}.ck .ck-widget .ck-widget__type-around__button.ck-widget__type-around__button_after{bottom:calc(-.5 * var(--ck-widget-outline-thickness));right:min(10%, 30px);transform:translateY(50%)}.ck .ck-widget:hover>.ck-widget__type-around>.ck-widget__type-around__button{opacity:1;pointer-events:auto}.ck .ck-widget:not(.ck-widget_selected)>.ck-widget__type-around>.ck-widget__type-around__button{background:var(--ck-color-widget-type-around-button-hover)}.ck .ck-widget.ck-widget_selected>.ck-widget__type-around>.ck-widget__type-around__button,.ck .ck-widget>.ck-widget__type-around>.ck-widget__type-around__button:hover{background:var(--ck-color-widget-type-around-button-active)}:is(.ck .ck-widget.ck-widget_selected>.ck-widget__type-around>.ck-widget__type-around__button, .ck .ck-widget>.ck-widget__type-around>.ck-widget__type-around__button:hover):after{width:calc(var(--ck-widget-type-around-button-size) - 2px);height:calc(var(--ck-widget-type-around-button-size) - 2px);content:"";z-index:calc(var(--ck-z-default) + 1);background:linear-gradient(135deg, #fff0 0%, #ffffff4d 100%);border-radius:100px;display:block;position:absolute;top:1px;left:1px}.ck .ck-widget.ck-widget_selected.ck-widget_type-around_show-fake-caret_before,.ck .ck-widget.ck-widget_selected.ck-widget_type-around_show-fake-caret_after{outline-color:#0000}.ck .ck-widget.ck-widget_selected>.ck-widget__type-around>.ck-widget__type-around__button{opacity:1;pointer-events:auto}.ck .ck-widget.ck-widget_with-selection-handle>.ck-widget__type-around>.ck-widget__type-around__button_before{margin-left:20px}.ck .ck-widget .ck-widget__type-around__fake-caret{pointer-events:none;background:var(--ck-color-base-text);outline:1px solid #ffffff80;height:1px;animation:1s linear infinite forwards ck-widget-type-around-fake-caret-pulse}:is(.ck .ck-widget.ck-widget_type-around_show-fake-caret_before, .ck .ck-widget.ck-widget_type-around_show-fake-caret_after).ck-widget_selected:hover{outline-color:var(--ck-color-widget-hover-border)}:is(.ck .ck-widget.ck-widget_type-around_show-fake-caret_before, .ck .ck-widget.ck-widget_type-around_show-fake-caret_after)>.ck-widget__type-around>.ck-widget__type-around__button{opacity:0;pointer-events:none}:is(:is(.ck .ck-widget.ck-widget_type-around_show-fake-caret_before, .ck .ck-widget.ck-widget_type-around_show-fake-caret_after).ck-widget_with-selection-handle.ck-widget_selected, :is(.ck .ck-widget.ck-widget_type-around_show-fake-caret_before, .ck .ck-widget.ck-widget_type-around_show-fake-caret_after).ck-widget_with-selection-handle.ck-widget_selected:hover)>.ck-widget__selection-handle{opacity:0}:is(.ck .ck-widget.ck-widget_type-around_show-fake-caret_before, .ck .ck-widget.ck-widget_type-around_show-fake-caret_after).ck-widget_selected.ck-widget_with-resizer>.ck-widget__resizer{opacity:0}.ck .ck-widget>.ck-widget__type-around>.ck-widget__type-around__fake-caret{display:none;position:absolute;left:0;right:0}.ck .ck-widget:hover>.ck-widget__type-around>.ck-widget__type-around__fake-caret{left:calc(-1 * var(--ck-widget-outline-thickness));right:calc(-1 * var(--ck-widget-outline-thickness))}.ck .ck-widget.ck-widget_type-around_show-fake-caret_before>.ck-widget__type-around>.ck-widget__type-around__fake-caret{top:calc(-1 * var(--ck-widget-outline-thickness) - 1px);display:block}.ck .ck-widget.ck-widget_type-around_show-fake-caret_after>.ck-widget__type-around>.ck-widget__type-around__fake-caret{bottom:calc(-1 * var(--ck-widget-outline-thickness) - 1px);display:block}.ck[dir="rtl"] .ck-widget.ck-widget_with-selection-handle .ck-widget__type-around>.ck-widget__type-around__button_before{margin-left:0;margin-right:20px}:is(.ck-editor__nested-editable.ck-editor__editable_selected .ck-widget.ck-widget_selected, .ck-editor__nested-editable.ck-editor__editable_selected .ck-widget:hover)>.ck-widget__type-around>.ck-widget__type-around__button{opacity:0;pointer-events:none}.ck .ck-widget:has(.ck-widget.table:hover)>.ck-widget__type-around>.ck-widget__type-around__button{opacity:0;pointer-events:none}.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected>.ck-widget__type-around>.ck-widget__type-around__button:not(:hover){background:var(--ck-color-widget-type-around-button-blurred-editable)}.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected>.ck-widget__type-around>.ck-widget__type-around__button:not(:hover) svg *{stroke:#999}@keyframes ck-widget-type-around-arrow-dash{0%{stroke-dashoffset:10px}20%,100%{stroke-dashoffset:0}}@keyframes ck-widget-type-around-arrow-tip-dash{0%,20%{stroke-dashoffset:7px}40%,100%{stroke-dashoffset:0}}@keyframes ck-widget-type-around-button-sonar{0%{box-shadow:0 0 0 0 hsla(var(--ck-color-focus-border-coordinates), var(--ck-color-widget-type-around-button-radar-start-alpha))}50%{box-shadow:0 0 0 5px hsla(var(--ck-color-focus-border-coordinates), var(--ck-color-widget-type-around-button-radar-end-alpha))}100%{box-shadow:0 0 0 5px hsla(var(--ck-color-focus-border-coordinates), var(--ck-color-widget-type-around-button-radar-start-alpha))}}@keyframes ck-widget-type-around-fake-caret-pulse{0%{opacity:1}49%{opacity:1}50%{opacity:0}99%{opacity:0}100%{opacity:1}}.ck.ck-editor__editable.ck-read-only .ck-widget__type-around,.ck.ck-editor__editable.ck-widget__type-around_disabled .ck-widget__type-around{display:none}.ck.ck-editor__editable.ck-restricted-editing_mode_restricted .ck-widget__type-around{display:none}.ck.ck-editor__editable.ck-restricted-editing_mode_restricted div.restricted-editing-exception .ck-widget__type-around{display:initial}:root{--ck-color-list-button-on-background: #EFF0EF;--ck-color-list-button-on-background-focus: #EFF0EF;--ck-color-list-button-hover-background: #EFF0EF;--ck-color-list-button-on-text: black;--ck-color-image-caption-background: transparent;--ck-spacing-small: 0.35rem;--ck-ui-component-min-height: 1rem;--ck-icon-size: 1.3rem;--ck-z-default: 9999;--ck-z-panel: calc( var(--ck-z-default) + 999 );--ck-z-dialog: calc( var(--ck-z-panel) + 9999 );--ck-text-tiny-font-size: 0.7rem;--ck-text-small-font-size: 0.85rem;--ck-text-big-font-size: 1.4rem;--ck-text-huge-font-size: 1.8rem;--ck-content-font-size: 1rem}.text-tiny{font-size:var(--ck-text-tiny-font-size)}.text-small{font-size:var(--ck-text-small-font-size)}.text-big{font-size:var(--ck-text-big-font-size)}.text-huge{font-size:var(--ck-text-huge-font-size)}.ck-editor{z-index:0}.ck-content .image img,.ibo-is-html-content .image img{min-width:inherit;margin-left:0;margin-right:0}.ck-content .image-style-align-left,.ibo-is-html-content .image-style-align-left,.ck-content .image-style-align-right,.ibo-is-html-content .image-style-align-right{display:block;float:unset}.ck-content .image-style-align-left,.ibo-is-html-content .image-style-align-left{text-align:left;margin-right:0}.ck-content .image-style-align-right,.ibo-is-html-content .image-style-align-right{text-align:right;margin-left:0}.ck-content figure,.ibo-is-html-content figure{margin-left:0;margin-right:0}.ck-content figure table,.ibo-is-html-content figure table{text-align:initial}.ck-content .table,.ibo-is-html-content .table{margin-left:0;margin-right:0}.ck-content .table table th,.ibo-is-html-content .table table th{background-color:#F4F4F4}.ck-content .marker-yellow,.ibo-is-html-content .marker-yellow{background-color:#FDFD77}.ck-content .marker-green,.ibo-is-html-content .marker-green{background-color:#62F962}.ck-content .marker-pink,.ibo-is-html-content .marker-pink{background-color:#FC7899}.ck-content .marker-blue,.ibo-is-html-content .marker-blue{background-color:#72CCFD}.ck.ck-fullscreen__main-wrapper .ck-fullscreen__sidebar{display:none}.ck-fullscreen__editable{display:flex;flex-direction:column;width:100%;margin:0;padding:0}.ck-table-show-hidden-borders{width:100%;max-width:100%;margin:0;border:0;padding:2em;flex-grow:1}.ck-fullscreen__main-wrapper .ck-fullscreen__editable-wrapper{--ck-fullscreen-editor-top-margin: 0;--ck-fullscreen-editor-bottom-margin: 0;flex-grow:1}.ck-fullscreen__main-wrapper .ck-fullscreen__editable::after{display:none}.ck.ck-fullscreen__right-edge{margin-left:0}.ck-fullscreen__main-wrapper .ck-fullscreen__editable .ck.ck-editor__editable:not(.ck-editor__nested-editable){height:100%;width:100%;max-width:100%;padding:0}:root{--ck-content-font-family: inherit;--ck-content-font-color: inherit;--ck-content-font-size: inherit;--ck-content-line-height: inherit;--ck-content-word-break: inherit;--ck-content-overflow-wrap: inherit}.ck{--ck-color-list-button-on-background: #e1e7ec;--ck-color-list-button-on-background-focus: #e1e7ec;--ck-color-list-button-hover-background: #e1e7ec;--ck-color-list-button-on-text: #212934;--ck-text-tiny-font-size: 0.67rem;--ck-text-small-font-size: 0.83rem;--ck-text-big-font-size: 1.33rem;--ck-text-huge-font-size: 1.83rem;--ck-color-image-caption-text: #212934}.ck-editor{width:100% !important;display:inline-grid;z-index:1}.ck-editor .ck-editor__main{overflow:auto}.ck.ck-content,.ck.ibo-is-html-content{color:#212934}.ck.ck-content .table table,.ck.ibo-is-html-content .table table{width:100% !important}.ck-editor__editable_inline:not(.ck-comment__input *){height:200px}.ck-content pre[data-language],.ibo-is-html-content pre[data-language]{padding:0 !important}.ck-content pre[data-language] code,.ibo-is-html-content pre[data-language] code{display:block;background:#212934 !important;padding:0.9rem !important;color:white !important}.ck-maximize_editor_main .ck-source-editing-area textarea{overflow:auto !important}.ck-mentions .ck-button{line-height:1.6rem;padding:4px 8px !important}.c3 path:not(.c3-legend-item-tile),.c3 line:not(.c3-legend-item-tile){stroke:#212934 !important}.c3-chart-arc path:not(.c3-legend-item-tile){stroke:white !important}.c3-axis{fill:#212934 !important}.c3-tooltip th{background-color:#aebecd !important;color:white !important}.c3-tooltip td{background-color:#929fb1 !important}.c3-legend-background{fill:white !important;stroke:#f2f2f2 !important}.c3-tooltip{background-color:#aebecd !important}.c3-tooltip tr{border:1px solid #CCC}.c3-legend-item{fill:#212934 !important}.tippy-content{white-space:pre-line}.ui-dialog{box-sizing:content-box;display:flex;flex-direction:column;position:absolute;top:0;left:0;background-color:white;border-radius:5px;overflow:hidden;outline:0;z-index:21}.ui-dialog .ui-dialog-titlebar{padding:0.4em 30px;position:relative;background-color:white;height:50px;border-bottom:solid 1px #e1e7ec;display:flex;flex-direction:row;align-items:center;justify-content:space-between}.ui-dialog .ui-dialog-title{float:left;margin:0.1em 0;width:100%;padding-right:24px}.ui-dialog .ui-dialog-titlebar-close{position:absolute;right:0;top:0.4em;width:20px;margin:-10px 0 0 0;padding:1px;height:20px}.ui-dialog .ui-dialog-content{box-sizing:content-box;position:relative;padding:16px 30px;overflow:auto}.ui-dialog .ui-dialog-buttonpane{margin-top:auto;text-align:left;border-width:1px 0 0 0;background-image:none;padding:0.4em 30px;position:relative;background-color:white;border-top:solid 1px #e1e7ec;height:50px}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right}.ui-dialog .ui-dialog-buttonpane button{margin:0.5em 0.4em 0.5em 0;cursor:pointer}.ui-dialog .ui-resizable-n{height:2px;top:0}.ui-dialog .ui-resizable-e{width:2px;right:0}.ui-dialog .ui-resizable-s{height:2px;bottom:0}.ui-dialog .ui-resizable-w{width:2px;left:0}.ui-dialog .ui-resizable-se{width:7px;height:7px;right:0;bottom:0}.ui-dialog .ui-resizable-sw{width:7px;height:7px;left:0;bottom:0}.ui-dialog .ui-resizable-ne{width:7px;height:7px;right:0;top:0}.ui-dialog .ui-resizable-nw{width:7px;height:7px;left:0;top:0}.ui-dialog .ui-button>.ui-icon{background-image:none;float:unset;margin:auto}.ui-dialog .ui-button>.ui-icon.ui-icon-closethick::after{content:"";font-family:"Font Awesome 5 Free";font-weight:600;text-indent:0;position:absolute;left:0px;width:100%;top:4px}.ui-button-icon-only{text-indent:-9999px;white-space:nowrap}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-widget-overlay.ui-front{position:fixed;top:0;left:0;width:100%;height:100%;opacity:0.6;filter:alpha(opacity=60);background-color:#37474f}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:0.1px;display:block;-ms-touch-action:none;touch-action:none}.ui-resizable-disabled .ui-resizable-handle{display:none}.ui-resizable-autohide .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.ui-layout-pane{overflow:auto}.ui-datepicker{display:none;background-color:white;border-radius:5px;box-shadow:0 1px 2px rgba(0, 0, 0, 0.25), 0 1px 3px rgba(0, 0, 0, 0.12);z-index:32 !important;padding:0 8px 5px 8px}.ui-datepicker .ui-datepicker-header{position:relative;margin:8px 8px 4px 8px;padding-top:24px}.ui-datepicker .ui-datepicker-prev,.ui-datepicker .ui-datepicker-next{position:absolute;top:0}.ui-datepicker .ui-datepicker-prev{left:0}.ui-datepicker .ui-datepicker-next{right:0}.ui-datepicker .ui-datepicker-title{display:flex;justify-content:space-evenly}.ui-datepicker .ui-datepicker-title select{flex-grow:1}.ui-datepicker .ui-datepicker-year{margin-left:8px}.ui-datepicker .ui-datepicker-calendar{margin:0 8px 8px 8px}.ui-datepicker th{padding:0.7em 0.3em;text-align:center;font-weight:bold}.ui-datepicker td{padding:1px}.ui-datepicker td span,.ui-datepicker td a{display:block;padding:0.2em 0;text-align:center;width:23px;border-radius:100%;color:#c05621}.ui-datepicker td span.ui-state-active,.ui-datepicker td a.ui-state-active{background-color:#c05621;color:floralwhite}.ui-datepicker td span.ui-state-highlight:not(.ui-state-active),.ui-datepicker td a.ui-state-highlight:not(.ui-state-active){background-color:#feebc8}.ui-datepicker td span.ui-state-hover:not(.ui-state-active),.ui-datepicker td a.ui-state-hover:not(.ui-state-active){color:#7b341e}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:0.7em 0 0 0;padding:0 0.2em;border-left:0;border-right:0;border-bottom:0}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:0.5em 0.2em 0.4em;cursor:pointer;padding:0.2em 0.6em 0.3em 0.6em;width:auto;overflow:visible}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto 0.4em}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-row-break{clear:both;width:100%;font-size:0}.ui-datepicker-rtl{direction:rtl}.ui-datepicker-rtl .ui-datepicker-prev{right:2px;left:auto}.ui-datepicker-rtl .ui-datepicker-prev:hover{right:1px;left:auto}.ui-datepicker-rtl .ui-datepicker-next{left:2px;right:auto}.ui-datepicker-rtl .ui-datepicker-next:hover{left:1px;right:auto}.ui-datepicker-rtl .ui-datepicker-buttonpane{clear:right}.ui-datepicker-rtl .ui-datepicker-buttonpane button{float:left}.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current{float:right}.ui-datepicker-rtl .ui-datepicker-group{float:right}.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-slider{position:relative;text-align:left;background-color:#f8f9fa;border:solid 1px #929fb1;border-radius:3px}.ui-slider .ui-slider-handle{background-color:white;border:solid 1px #929fb1;border-radius:3px;position:absolute;z-index:2;width:1.4em;height:1.4em;-ms-touch-action:none;touch-action:none;cursor:pointer}.ui-slider .ui-slider-handle:hover,.ui-slider .ui-slider-handle:active{border:solid 1px #c05621}.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:0.7em;display:block;background-position:0 0}.ui-slider.ui-state-disabled .ui-slider-handle{filter:inherit}.ui-slider.ui-state-disabled .ui-slider-range{filter:inherit}.ui-slider-horizontal{height:0.8em}.ui-slider-horizontal .ui-slider-handle{top:-0.2em;margin-left:-0.6em}.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:0.8em;height:100px}.ui-slider-vertical .ui-slider-handle{left:-0.3em;margin-left:0;margin-bottom:-0.6em}.ui-slider-vertical .ui-slider-range{left:0;width:100%}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default;z-index:100}.ui-autocomplete .ui-menu-item{padding:0}.ui-autocomplete-input{width:auto;display:inline}.ui-helper-hidden-accessible{clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-tabs-tab.ui-state-disabled a{cursor:not-allowed !important}.ui-multiselect{width:auto !important;padding-left:0.7em !important;padding-right:1.5em !important;text-align:left;white-space:nowrap;overflow:hidden;display:grid}button.ui-multiselect>span{overflow:hidden}.ui-multiselect span.ui-icon{float:right}.ui-multiselect-single .ui-multiselect-checkboxes input{position:absolute !important;top:auto !important;left:-9999px}.ui-multiselect-single .ui-multiselect-checkboxes label{padding:5px !important}.ui-multiselect-header{margin-bottom:3px;padding:3px 0}.ui-multiselect-header ul{padding-left:24px}.ui-multiselect-header ul li{float:left;padding:0 10px 0 0}.ui-multiselect-header span.ui-icon{float:left}.ui-multiselect-header li.ui-multiselect-close{float:right;text-align:right;padding-right:0}.ui-multiselect-menu{display:none;padding:3px;position:absolute;z-index:10000;text-align:left}.ui-multiselect-checkboxes{position:relative;overflow-y:scroll !important}.ui-multiselect-checkboxes label{display:flex;align-items:center;cursor:pointer;padding:3px 1px}.ui-multiselect-checkboxes label input{margin-right:5px;position:relative;top:1px}.ui-multiselect-checkboxes li{clear:both;padding-right:3px}.ui-multiselect-checkboxes li.ui-multiselect-optgroup-label{text-align:center}.ui-multiselect-checkboxes li.ui-multiselect-optgroup-label a{display:block;padding:3px;margin:1px 0;text-decoration:none}.ui-dialog-titlebar.ui-multiselect-header{padding-left:20px;padding-right:20px}.ui-dialog-titlebar.ui-multiselect-header ul{padding-left:0;width:100%}.ui-dialog-titlebar.ui-multiselect-header a{color:#212934;font-weight:normal}.ui-multiselect,.ui-multiselect-menu,.ui-multiselect-header{background-color:#f8f9fa}button.ui-multiselect{padding-right:10px !important}button.ui-multiselect .fas{float:right;padding-left:10px}.dataTables_paginate{color:#404b5a}.dataTables_paginate a.paginate_button{display:inline-flex;justify-content:center;align-items:center;padding:0 5px;min-width:20px;height:20px;border-radius:3px}.dataTables_paginate a.paginate_button:hover{background-color:#f8f9fa}.dataTables_paginate a.paginate_button.disabled{color:#929fb1;background-color:transparent;cursor:default}.dataTables_paginate a.paginate_button.current{color:#212934;background-color:#e1e7ec;box-shadow:inset 0px 1px 0px rgba(0, 0, 0, 0.15)}.dataTables_length select{}.dataTables_length select[aria-controls]{display:inline-flex;width:unset;min-width:50px;height:20px;padding:0 4px}.dataTables_scrollHead{}.dataTables_scrollHead thead tr th{cursor:pointer}.dataTables_scrollHead thead tr th.sorting::after{position:absolute;right:calc((12px - 8px) / 2);content:"";opacity:0.3;line-height:inherit}.dataTables_scrollHead thead tr th.sorting_asc:after{content:"";opacity:1}.dataTables_scrollHead thead tr th.sorting_desc:after{content:"";opacity:1}.dataTables_scrollHeadInner{border-bottom:1px solid #ccd4db}.dataTable th,.dataTable td{position:relative;padding:10px 12px}.dataTable tr:nth-child(odd){background-color:white}.dataTable tr:nth-child(even){background-color:#f2f2f2}.dataTable tr.ibo-is-red{background-color:#fce8e8}.dataTable tr.ibo-is-danger{background-color:#fed7d7}.dataTable tr.ibo-is-alert{background-color:#fed7d7}.dataTable tr.ibo-is-orange{background-color:floralwhite}.dataTable tr.ibo-is-warning{background-color:#feebc8}.dataTable tr.ibo-is-blue{background-color:#bee3f8}.dataTable tr.ibo-is-info{background-color:#bee3f8}.dataTable tr.ibo-is-green{background-color:#dcedc8}.dataTable tr.ibo-is-success{background-color:#c5e1a5}.dataTable tr.ibo-is-red td:first-child::before{content:"";position:absolute;left:0;top:0;width:3px;height:100%;background-color:#feb2b2}.dataTable tr.ibo-is-danger td:first-child::before{content:"";position:absolute;left:0;top:0;width:3px;height:100%;background-color:#fc8181}.dataTable tr.ibo-is-alert td:first-child::before{content:"";position:absolute;left:0;top:0;width:3px;height:100%;background-color:#fc8181}.dataTable tr.ibo-is-orange td:first-child::before{content:"";position:absolute;left:0;top:0;width:3px;height:100%;background-color:#fbd38d}.dataTable tr.ibo-is-warning td:first-child::before{content:"";position:absolute;left:0;top:0;width:3px;height:100%;background-color:#f6ae55}.dataTable tr.ibo-is-blue td:first-child::before{content:"";position:absolute;left:0;top:0;width:3px;height:100%;background-color:#63b4ed}.dataTable tr.ibo-is-info td:first-child::before{content:"";position:absolute;left:0;top:0;width:3px;height:100%;background-color:#63b4ed}.dataTable tr.ibo-is-green td:first-child::before{content:"";position:absolute;left:0;top:0;width:3px;height:100%;background-color:#aed581}.dataTable tr.ibo-is-success td:first-child::before{content:"";position:absolute;left:0;top:0;width:3px;height:100%;background-color:#aed581}.treeview,.treeview ul{padding:0;margin:0;list-style:none}.treeview div.hitarea{height:15px;width:15px;margin-left:-15px;float:left;cursor:pointer}.treeview li{margin:0;padding:3px 0 3px 16px}.treeview a.selected{background-color:#f8f9fa}#treecontrol{margin:1em 0}.treeview .hover{color:#dd6c20;cursor:pointer}.treeview li{background:url("..//images/tv-item.gif") 0 0 no-repeat}.treeview .collapsable{background-image:url("..//images/tv-collapsable.gif")}.treeview .expandable{background-image:url("..//images/tv-expandable.gif")}.treeview .last{background-image:url("..//images/tv-item-last.gif")}.treeview .lastCollapsable{background-image:url("..//images/tv-collapsable-last.gif")}.treeview .lastExpandable{background-image:url("..//images/tv-expandable-last.gif")}.filetree li{padding:3px 0 1px 16px}.filetree span.folder,.filetree span.file{padding-left:16px;display:block;height:15px}.filetree span.folder{background:url("..//images/tv-folder.gif") 0 0 no-repeat}.filetree span.file{background:url("..//images/tv-file.gif") 0 0 no-repeat}.blockUI.blockOverlay{background-color:#f2f2f2}.blockUI.blockMsg{font-size:6em;text-align:center;color:#6e7a8a;border:none;background-color:transparent}.mfp-bg{z-index:1100}.mfp-wrap{z-index:1101}.selectize-dropdown,.selectize-input,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active,.selectize-input input,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active input{color:#212934}.selectize-control.single .selectize-input,.selectize-control.single .ibo-quick-create--input.selectize-control.single .selectize-input.input-active,.ibo-quick-create--input.selectize-control.single .selectize-control.single .selectize-input.input-active{box-shadow:unset;background-color:white;background-image:unset;background-repeat:unset}.selectize-input,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active,.selectize-control.single .selectize-input.input-active,.selectize-control.single .ibo-quick-create--input.selectize-control.single .selectize-input.input-active,.ibo-quick-create--input.selectize-control.single .selectize-control.single .selectize-input.input-active{background:unset;background-color:white;cursor:text;display:inline-flex}.selectize-control.single .selectize-input.dropdown-active:after,.selectize-control.single .ibo-quick-create--input.selectize-control.single .dropdown-active.selectize-input.input-active:after,.ibo-quick-create--input.selectize-control.single .selectize-control.single .dropdown-active.selectize-input.input-active:after{margin-top:unset;border-width:unset;border-color:unset}.selectize-control.single .selectize-input:after,.selectize-control.single .ibo-quick-create--input.selectize-control.single .selectize-input.input-active:after,.ibo-quick-create--input.selectize-control.single .selectize-control.single .selectize-input.input-active:after,.selectize-control.single .selectize-input:not(.no-arrow):after,.selectize-control.single .ibo-quick-create--input.selectize-control.single .selectize-input.input-active:not(.no-arrow):after,.ibo-quick-create--input.selectize-control.single .selectize-control.single .selectize-input.input-active:not(.no-arrow):after{content:unset}.selectize-input::after,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active::after{content:unset}.selectize-input>*,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active>*{display:inline-flex}.selectize-control.single .selectize-input,.selectize-control.single .ibo-quick-create--input.selectize-control.single .selectize-input.input-active,.ibo-quick-create--input.selectize-control.single .selectize-control.single .selectize-input.input-active,.selectize-dropdown.single{border-color:#aebecd}.selectize-dropdown{background-color:white;color:#212934}.selectize-dropdown .selected,.selectize-dropdown .active,.selectize-dropdown .active:not(.selected){background:#ebf8ff;color:#212934}.selectize-dropdown [data-selectable],.selectize-dropdown .optgroup-header{padding:5px 8px}.selectize-dropdown .option{opacity:1}.selectize-add-option{display:inline-flex;justify-content:center;align-items:flex-end;position:absolute;right:0;padding-bottom:10px;height:100%;width:24px;z-index:1;color:#212934}.selectize-input .attribute-set-item>*,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active .attribute-set-item>*{display:inline}.selectize-input .attribute-set-item.item-add::before,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active .attribute-set-item.item-add::before,.selectize-input .attribute-set-item.item-remove::before,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active .attribute-set-item.item-remove::before{margin-right:4px}.selectize-input .attribute-set-item.item-add,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active .attribute-set-item.item-add{background-color:#dcedc8 !important}.selectize-input .attribute-set-item.item-add::before,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active .attribute-set-item.item-add::before{color:#33691e;content:""}.selectize-input .attribute-set-item.item-remove,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active .attribute-set-item.item-remove{background-color:#fce8e8 !important}.selectize-input .attribute-set-item.item-remove::before,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active .attribute-set-item.item-remove::before{color:#9b2c2c;content:""}.selectize-input .attribute-set-item.item-ignore-partial,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active .attribute-set-item.item-ignore-partial{background-color:#e1e7ec !important}.selectize-input.selectize-input-error,.ibo-quick-create--input.selectize-control.single .selectize-input-error.selectize-input.input-active{border:1px solid #e53e3e}.toastify.on{opacity:1}.toast-close{background:transparent;border:0;color:inherit;cursor:pointer;font-family:inherit;padding:0;margin-left:8px}.toastify-right{right:16px}.toastify-left{left:16px}.toastify-top{top:-150px}.toastify-bottom{bottom:-150px}.toastify-rounded{border-radius:25px}.toastify-avatar{width:1.5em;height:1.5em;margin:-7px 5px;border-radius:2px}.toastify-center{margin-left:auto;margin-right:auto;left:0;right:0;max-width:fit-content;max-width:-moz-fit-content}@media only screen and (max-width:360px){.toastify-right,.toastify-left{margin-left:auto;margin-right:auto;left:0;right:0;max-width:fit-content}}:root{--ibo-scrollbar--scrollbar-width: 8px;--ibo-scrollbar--scrollbar-height: 8px;--ibo-scrollbar--scrollbar-track-background-color: rgba(255, 255, 255, 0);--ibo-scrollbar--scrollbar-track-border-radius: 5px;--ibo-scrollbar--scrollbar-thumb-background-color: #d5dde5;--ibo-scrollbar--scrollbar-thumb-border: none;--ibo-scrollbar--scrollbar-thumb-border-radius: 5px}*,*::before,*::after{box-sizing:border-box}*{scrollbar-width:thin;scrollbar-color:var(--ibo-scrollbar--scrollbar-thumb-background-color) var(--ibo-scrollbar--scrollbar-track-background-color)}*::-webkit-scrollbar{width:var(--ibo-scrollbar--scrollbar-width);height:var(--ibo-scrollbar--scrollbar-height)}*::-webkit-scrollbar-track{background-color:var(--ibo-scrollbar--scrollbar-track-background-color);border-radius:var(--ibo-scrollbar--scrollbar-track-border-radius)}* ::-webkit-scrollbar-thumb{background-color:var(--ibo-scrollbar--scrollbar-thumb-background-color);border:var(--ibo-scrollbar--scrollbar-thumb-border);border-radius:var(--ibo-scrollbar--scrollbar-thumb-border-radius)}html{font-size:12px}a{color:var(--ibo-hyperlink-color);text-decoration:var(--ibo-hyperlink-text-decoration)}a:hover,a:active,a:visited{text-decoration:var(--ibo-hyperlink-text-decoration)}a:hover{color:var(--ibo-hyperlink-color--on-hover);text-decoration:var(--ibo-hyperlink-text-decoration--on-hover)}a:active{color:var(--ibo-hyperlink-color--on-active);text-decoration:var(--ibo-hyperlink-text-decoration--on-active)}.ibo-alert.ibo-is-primary{background-color:#feebc8;color:#7b341e}.ibo-alert.ibo-is-primary a{color:#7b341e}.ibo-alert.ibo-is-primary::before{background-color:#c05621}.ibo-alert.ibo-is-secondary,.ui-dialog .ibo-alert.ui-button,.ibo-alert.ui-datepicker-current,.ibo-alert.ui-datepicker-close{background-color:#e1e7ec;color:#212934}.ibo-alert.ibo-is-secondary a,.ui-dialog .ibo-alert.ui-button a,.ibo-alert.ui-datepicker-current a,.ibo-alert.ui-datepicker-close a{color:#212934}.ibo-alert.ibo-is-secondary::before,.ui-dialog .ibo-alert.ui-button::before,.ibo-alert.ui-datepicker-current::before,.ibo-alert.ui-datepicker-close::before{background-color:#6e7a8a}.ibo-alert.ibo-is-neutral,.ui-dialog .ibo-alert.ui-button.ui-dialog-titlebar-close{background-color:#e1e7ec;color:#212934}.ibo-alert.ibo-is-neutral a,.ui-dialog .ibo-alert.ui-button.ui-dialog-titlebar-close a{color:#212934}.ibo-alert.ibo-is-neutral::before,.ui-dialog .ibo-alert.ui-button.ui-dialog-titlebar-close::before{background-color:#6e7a8a}.ibo-toast.ibo-is-information,.ibo-alert.ibo-is-information{background-color:#bee3f8;color:#2a4265}.ibo-toast.ibo-is-information a,.ibo-alert.ibo-is-information a{color:#2a4265}.ibo-toast.ibo-is-information::before,.ibo-alert.ibo-is-information::before{background-color:#2b6bb0}.ibo-toast.ibo-is-success,.ibo-alert.ibo-is-success{background-color:#dcedc8;color:#33691e}.ibo-toast.ibo-is-success a,.ibo-alert.ibo-is-success a{color:#33691e}.ibo-toast.ibo-is-success::before,.ibo-alert.ibo-is-success::before{background-color:#689f38}.ibo-alert.ibo-is-failure{background-color:#fed7d7;color:#742a2a}.ibo-alert.ibo-is-failure a{color:#742a2a}.ibo-alert.ibo-is-failure::before{background-color:#c53030}.ibo-toast.ibo-is-warning,.ibo-alert.ibo-is-warning{background-color:#feebc8;color:#7b341e}.ibo-toast.ibo-is-warning a,.ibo-alert.ibo-is-warning a{color:#7b341e}.ibo-toast.ibo-is-warning::before,.ibo-alert.ibo-is-warning::before{background-color:#c05621}.ibo-toast.ibo-is-error,.ibo-alert.ibo-is-danger{background-color:#fed7d7;color:#742a2a}.ibo-toast.ibo-is-error a,.ibo-alert.ibo-is-danger a{color:#742a2a}.ibo-toast.ibo-is-error::before,.ibo-alert.ibo-is-danger::before{background-color:#c53030}.ibo-alert.ibo-is-grey{background-color:#e1e7ec;color:#212934}.ibo-alert.ibo-is-grey a{color:#212934}.ibo-alert.ibo-is-grey::before{background-color:#6e7a8a}.ibo-alert.ibo-is-blue-grey{background-color:#b0bec5;color:#263238}.ibo-alert.ibo-is-blue-grey a{color:#263238}.ibo-alert.ibo-is-blue-grey::before{background-color:#455a64}.ibo-alert.ibo-is-blue{background-color:#bee3f8;color:#2a4265}.ibo-alert.ibo-is-blue a{color:#2a4265}.ibo-alert.ibo-is-blue::before{background-color:#2b6bb0}.ibo-alert.ibo-is-cyan{background-color:#c9eef2;color:#006164}.ibo-alert.ibo-is-cyan a{color:#006164}.ibo-alert.ibo-is-cyan::before{background-color:#2b6bb0}.ibo-alert.ibo-is-green{background-color:#dcedc8;color:#33691e}.ibo-alert.ibo-is-green a{color:#33691e}.ibo-alert.ibo-is-green::before{background-color:#689f38}.ibo-alert.ibo-is-orange{background-color:#feebc8;color:#7b341e}.ibo-alert.ibo-is-orange a{color:#7b341e}.ibo-alert.ibo-is-orange::before{background-color:#c05621}.ibo-alert.ibo-is-red{background-color:#fed7d7;color:#742a2a}.ibo-alert.ibo-is-red a{color:#742a2a}.ibo-alert.ibo-is-red::before{background-color:#c53030}.ibo-alert.ibo-is-pink{background-color:#fed7e2;color:#702459}.ibo-alert.ibo-is-pink a{color:#702459}.ibo-alert.ibo-is-pink::before{background-color:#b83280}.ibo-alert{position:relative;padding:18px 20px;min-height:30px;border-radius:3px;overflow:hidden}.ibo-alert::before{display:block;position:absolute;top:0;left:0;content:"";width:4px;height:100%}.ibo-alert .ibo-alert--title{cursor:pointer}.ibo-alert.ibo-is-opened .ibo-alert--minimize-button,.ibo-alert.ibo-input-select-icon--menu .ibo-alert--minimize-button{display:block}.ibo-alert.ibo-is-opened .ibo-alert--maximize-button,.ibo-alert.ibo-input-select-icon--menu .ibo-alert--maximize-button{display:none}.ibo-alert:not(.ibo-is-opened){padding:5px 20px}.ibo-alert:not(.ibo-is-opened) .ibo-alert--title{padding-bottom:0}.ibo-alert:not(.ibo-is-opened) .ibo-alert--minimize-button{display:none}.ibo-alert:not(.ibo-is-opened) .ibo-alert--maximize-button{display:block}.ibo-alert:not(.ibo-is-opened) .ibo-alert--body{display:none}.ibo-alert--title+.ibo-alert--body{margin-top:4px}.ibo-alert--action-button{position:absolute;cursor:pointer;top:5px}.ibo-alert--action-button:hover i{opacity:0.8}.ibo-alert--action-button.ibo-alert--maximize-button,.ibo-alert--action-button.ibo-alert--minimize-button{right:30px}.ibo-alert--action-button.ibo-alert--close-button{right:10px}.ibo-button.ibo-is-regular.ibo-is-neutral,.ui-dialog .ibo-is-regular.ibo-is-neutral.ui-button,.ui-dialog .ibo-is-neutral.ui-button,.ui-dialog .ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-is-neutral.ui-button.ui-datepicker-current,.ui-dialog .ui-button.ui-datepicker-current.ui-dialog-titlebar-close,.ui-dialog .ibo-is-neutral.ui-button.ui-datepicker-close,.ui-dialog .ui-button.ui-datepicker-close.ui-dialog-titlebar-close,.ui-dialog .ibo-is-regular.ui-button.ui-dialog-titlebar-close,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close,.ibo-is-regular.ibo-is-neutral.ui-datepicker-current,.ui-dialog .ibo-is-neutral.ui-datepicker-current.ui-button,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close,.ibo-is-neutral.ui-datepicker-current,.ibo-is-neutral.ui-datepicker-current.ui-datepicker-close,.ui-dialog .ui-datepicker-current.ui-datepicker-close.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-is-regular.ui-datepicker-current.ui-button.ui-dialog-titlebar-close,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close.ui-datepicker-close,.ibo-is-regular.ibo-is-neutral.ui-datepicker-close,.ui-dialog .ibo-is-neutral.ui-datepicker-close.ui-button,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close,.ibo-is-neutral.ui-datepicker-close.ui-datepicker-current,.ui-dialog .ui-datepicker-close.ui-datepicker-current.ui-button.ui-dialog-titlebar-close,.ibo-is-neutral.ui-datepicker-close,.ui-dialog .ibo-is-regular.ui-datepicker-close.ui-button.ui-dialog-titlebar-close,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close.ui-datepicker-current,.ui-dialog .ibo-button.ibo-is-neutral.ui-button,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close,.ibo-button.ibo-is-neutral.ui-datepicker-current,.ui-dialog .ibo-button.ui-datepicker-current.ui-button.ui-dialog-titlebar-close,.ibo-button.ibo-is-neutral.ui-datepicker-close,.ui-dialog .ibo-button.ui-datepicker-close.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-button.ibo-is-regular.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-is-regular.ui-button.ui-dialog-titlebar-close.ui-datepicker-current,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current.ui-datepicker-close,.ui-dialog .ibo-is-regular.ui-button.ui-dialog-titlebar-close.ui-datepicker-close,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close.ui-datepicker-current,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close.ui-datepicker-current,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close.ui-datepicker-close{background-color:#f8f9fa;color:#212934;box-shadow:0px 2px 0px #d5dde5}.ibo-button.ibo-is-regular.ibo-is-neutral:hover,.ui-dialog .ibo-is-regular.ibo-is-neutral.ui-button:hover,.ui-dialog .ibo-is-neutral.ui-button:hover,.ui-dialog .ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-is-neutral.ui-button.ui-datepicker-current:hover,.ui-dialog .ui-button.ui-datepicker-current.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-is-neutral.ui-button.ui-datepicker-close:hover,.ui-dialog .ui-button.ui-datepicker-close.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-is-regular.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current:hover,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close:hover,.ibo-is-regular.ibo-is-neutral.ui-datepicker-current:hover,.ui-dialog .ibo-is-neutral.ui-datepicker-current.ui-button:hover,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close:hover,.ibo-is-neutral.ui-datepicker-current:hover,.ibo-is-neutral.ui-datepicker-current.ui-datepicker-close:hover,.ui-dialog .ui-datepicker-current.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-is-regular.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:hover,.ibo-is-regular.ibo-is-neutral.ui-datepicker-close:hover,.ui-dialog .ibo-is-neutral.ui-datepicker-close.ui-button:hover,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close:hover,.ibo-is-neutral.ui-datepicker-close.ui-datepicker-current:hover,.ui-dialog .ui-datepicker-close.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:hover,.ibo-is-neutral.ui-datepicker-close:hover,.ui-dialog .ibo-is-regular.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:hover,.ui-dialog .ibo-button.ibo-is-neutral.ui-button:hover,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close:hover,.ibo-button.ibo-is-neutral.ui-datepicker-current:hover,.ui-dialog .ibo-button.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:hover,.ibo-button.ibo-is-neutral.ui-datepicker-close:hover,.ui-dialog .ibo-button.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-button.ibo-is-regular.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-is-regular.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:hover,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current.ui-datepicker-close:hover,.ui-dialog .ibo-is-regular.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:hover,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close.ui-datepicker-current:hover,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:hover,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:hover{background-color:#e1e7ec;color:#212934;box-shadow:0px 2px 0px #d5dde5}.ibo-button.ibo-is-regular.ibo-is-neutral:active,.ui-dialog .ibo-is-regular.ibo-is-neutral.ui-button:active,.ui-dialog .ibo-is-neutral.ui-button:active,.ui-dialog .ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-is-neutral.ui-button.ui-datepicker-current:active,.ui-dialog .ui-button.ui-datepicker-current.ui-dialog-titlebar-close:active,.ui-dialog .ibo-is-neutral.ui-button.ui-datepicker-close:active,.ui-dialog .ui-button.ui-datepicker-close.ui-dialog-titlebar-close:active,.ui-dialog .ibo-is-regular.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current:active,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close:active,.ibo-is-regular.ibo-is-neutral.ui-datepicker-current:active,.ui-dialog .ibo-is-neutral.ui-datepicker-current.ui-button:active,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close:active,.ibo-is-neutral.ui-datepicker-current:active,.ibo-is-neutral.ui-datepicker-current.ui-datepicker-close:active,.ui-dialog .ui-datepicker-current.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-is-regular.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:active,.ibo-is-regular.ibo-is-neutral.ui-datepicker-close:active,.ui-dialog .ibo-is-neutral.ui-datepicker-close.ui-button:active,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close:active,.ibo-is-neutral.ui-datepicker-close.ui-datepicker-current:active,.ui-dialog .ui-datepicker-close.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:active,.ibo-is-neutral.ui-datepicker-close:active,.ui-dialog .ibo-is-regular.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:active,.ui-dialog .ibo-button.ibo-is-neutral.ui-button:active,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close:active,.ibo-button.ibo-is-neutral.ui-datepicker-current:active,.ui-dialog .ibo-button.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:active,.ibo-button.ibo-is-neutral.ui-datepicker-close:active,.ui-dialog .ibo-button.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-button.ibo-is-regular.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-is-regular.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:active,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current.ui-datepicker-close:active,.ui-dialog .ibo-is-regular.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:active,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close.ui-datepicker-current:active,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:active,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:active{background-color:#e1e7ec;color:#212934;box-shadow:inset 0px 2px 0px #d5dde5 , 0px 2px 0px #e1e7ec}.ibo-button.ibo-is-regular.ibo-is-neutral:disabled,.ui-dialog .ibo-is-regular.ibo-is-neutral.ui-button:disabled,.ui-dialog .ibo-is-neutral.ui-button:disabled,.ui-dialog .ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-is-neutral.ui-button.ui-datepicker-current:disabled,.ui-dialog .ui-button.ui-datepicker-current.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-is-neutral.ui-button.ui-datepicker-close:disabled,.ui-dialog .ui-button.ui-datepicker-close.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-is-regular.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current:disabled,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close:disabled,.ibo-is-regular.ibo-is-neutral.ui-datepicker-current:disabled,.ui-dialog .ibo-is-neutral.ui-datepicker-current.ui-button:disabled,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close:disabled,.ibo-is-neutral.ui-datepicker-current:disabled,.ibo-is-neutral.ui-datepicker-current.ui-datepicker-close:disabled,.ui-dialog .ui-datepicker-current.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-is-regular.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:disabled,.ibo-is-regular.ibo-is-neutral.ui-datepicker-close:disabled,.ui-dialog .ibo-is-neutral.ui-datepicker-close.ui-button:disabled,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close:disabled,.ibo-is-neutral.ui-datepicker-close.ui-datepicker-current:disabled,.ui-dialog .ui-datepicker-close.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:disabled,.ibo-is-neutral.ui-datepicker-close:disabled,.ui-dialog .ibo-is-regular.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:disabled,.ui-dialog .ibo-button.ibo-is-neutral.ui-button:disabled,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close:disabled,.ibo-button.ibo-is-neutral.ui-datepicker-current:disabled,.ui-dialog .ibo-button.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:disabled,.ibo-button.ibo-is-neutral.ui-datepicker-close:disabled,.ui-dialog .ibo-button.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-button.ibo-is-regular.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-is-regular.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:disabled,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current.ui-datepicker-close:disabled,.ui-dialog .ibo-is-regular.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:disabled,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close.ui-datepicker-current:disabled,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:disabled,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:disabled{background-color:#d5dde5;color:#6e7a8a;box-shadow:inset 0px 2px 0px #d5dde5}.ibo-button.ibo-is-regular.ibo-is-primary,.ui-dialog .ibo-is-regular.ibo-is-primary.ui-button,.ui-dialog .ibo-is-primary.ui-button,.ui-dialog .ibo-is-primary.ui-button.ui-datepicker-current,.ui-dialog .ibo-is-primary.ui-button.ui-datepicker-close,.ibo-is-regular.ibo-is-primary.ui-datepicker-current,.ui-dialog .ibo-is-primary.ui-datepicker-current.ui-button,.ibo-is-primary.ui-datepicker-current,.ibo-is-primary.ui-datepicker-current.ui-datepicker-close,.ibo-is-regular.ibo-is-primary.ui-datepicker-close,.ui-dialog .ibo-is-primary.ui-datepicker-close.ui-button,.ibo-is-primary.ui-datepicker-close.ui-datepicker-current,.ibo-is-primary.ui-datepicker-close,.ui-dialog .ibo-button.ibo-is-primary.ui-button,.ibo-button.ibo-is-primary.ui-datepicker-current,.ibo-button.ibo-is-primary.ui-datepicker-close{background-color:#00838f;color:white;box-shadow:0px 2px 0px #003636}.ibo-button.ibo-is-regular.ibo-is-primary:hover,.ui-dialog .ibo-is-regular.ibo-is-primary.ui-button:hover,.ui-dialog .ibo-is-primary.ui-button:hover,.ui-dialog .ibo-is-primary.ui-button.ui-datepicker-current:hover,.ui-dialog .ibo-is-primary.ui-button.ui-datepicker-close:hover,.ibo-is-regular.ibo-is-primary.ui-datepicker-current:hover,.ui-dialog .ibo-is-primary.ui-datepicker-current.ui-button:hover,.ibo-is-primary.ui-datepicker-current:hover,.ibo-is-primary.ui-datepicker-current.ui-datepicker-close:hover,.ibo-is-regular.ibo-is-primary.ui-datepicker-close:hover,.ui-dialog .ibo-is-primary.ui-datepicker-close.ui-button:hover,.ibo-is-primary.ui-datepicker-close.ui-datepicker-current:hover,.ibo-is-primary.ui-datepicker-close:hover,.ui-dialog .ibo-button.ibo-is-primary.ui-button:hover,.ibo-button.ibo-is-primary.ui-datepicker-current:hover,.ibo-button.ibo-is-primary.ui-datepicker-close:hover{background-color:#006164;color:white;box-shadow:0px 2px 0px #003636}.ibo-button.ibo-is-regular.ibo-is-primary:active,.ui-dialog .ibo-is-regular.ibo-is-primary.ui-button:active,.ui-dialog .ibo-is-primary.ui-button:active,.ui-dialog .ibo-is-primary.ui-button.ui-datepicker-current:active,.ui-dialog .ibo-is-primary.ui-button.ui-datepicker-close:active,.ibo-is-regular.ibo-is-primary.ui-datepicker-current:active,.ui-dialog .ibo-is-primary.ui-datepicker-current.ui-button:active,.ibo-is-primary.ui-datepicker-current:active,.ibo-is-primary.ui-datepicker-current.ui-datepicker-close:active,.ibo-is-regular.ibo-is-primary.ui-datepicker-close:active,.ui-dialog .ibo-is-primary.ui-datepicker-close.ui-button:active,.ibo-is-primary.ui-datepicker-close.ui-datepicker-current:active,.ibo-is-primary.ui-datepicker-close:active,.ui-dialog .ibo-button.ibo-is-primary.ui-button:active,.ibo-button.ibo-is-primary.ui-datepicker-current:active,.ibo-button.ibo-is-primary.ui-datepicker-close:active{background-color:#006164;color:white;box-shadow:inset 0px 2px 0px #003636 , 0px 2px 0px #006164}.ibo-button.ibo-is-regular.ibo-is-primary:disabled,.ui-dialog .ibo-is-regular.ibo-is-primary.ui-button:disabled,.ui-dialog .ibo-is-primary.ui-button:disabled,.ui-dialog .ibo-is-primary.ui-button.ui-datepicker-current:disabled,.ui-dialog .ibo-is-primary.ui-button.ui-datepicker-close:disabled,.ibo-is-regular.ibo-is-primary.ui-datepicker-current:disabled,.ui-dialog .ibo-is-primary.ui-datepicker-current.ui-button:disabled,.ibo-is-primary.ui-datepicker-current:disabled,.ibo-is-primary.ui-datepicker-current.ui-datepicker-close:disabled,.ibo-is-regular.ibo-is-primary.ui-datepicker-close:disabled,.ui-dialog .ibo-is-primary.ui-datepicker-close.ui-button:disabled,.ibo-is-primary.ui-datepicker-close.ui-datepicker-current:disabled,.ibo-is-primary.ui-datepicker-close:disabled,.ui-dialog .ibo-button.ibo-is-primary.ui-button:disabled,.ibo-button.ibo-is-primary.ui-datepicker-current:disabled,.ibo-button.ibo-is-primary.ui-datepicker-close:disabled{background-color:#d5dde5;color:#6e7a8a;box-shadow:inset 0px 2px 0px #d5dde5}.ibo-button.ibo-is-regular.ibo-is-secondary,.ui-dialog .ibo-is-regular.ibo-is-secondary.ui-button,.ui-dialog .ibo-is-secondary.ui-button,.ui-dialog .ui-button,.ui-dialog .ui-button.ui-datepicker-current,.ui-dialog .ui-button.ui-datepicker-close,.ui-dialog .ibo-is-secondary.ui-button.ui-datepicker-current,.ui-dialog .ui-button.ui-datepicker-current.ui-datepicker-close,.ui-dialog .ibo-is-secondary.ui-button.ui-datepicker-close,.ui-dialog .ui-button.ui-datepicker-close.ui-datepicker-current,.ui-dialog .ibo-is-regular.ui-button,.ui-dialog .ibo-is-regular.ui-button.ui-datepicker-current,.ui-dialog .ibo-is-regular.ui-button.ui-datepicker-close,.ibo-is-regular.ibo-is-secondary.ui-datepicker-current,.ui-dialog .ibo-is-secondary.ui-datepicker-current.ui-button,.ui-dialog .ui-datepicker-current.ui-button,.ui-dialog .ui-datepicker-current.ui-button.ui-datepicker-close,.ibo-is-secondary.ui-datepicker-current,.ui-datepicker-current,.ui-datepicker-current.ui-datepicker-close,.ibo-is-secondary.ui-datepicker-current.ui-datepicker-close,.ui-dialog .ui-datepicker-current.ui-datepicker-close.ui-button,.ui-dialog .ibo-is-regular.ui-datepicker-current.ui-button,.ibo-is-regular.ui-datepicker-current,.ibo-is-regular.ui-datepicker-current.ui-datepicker-close,.ibo-is-regular.ibo-is-secondary.ui-datepicker-close,.ui-dialog .ibo-is-secondary.ui-datepicker-close.ui-button,.ui-dialog .ui-datepicker-close.ui-button,.ui-dialog .ui-datepicker-close.ui-button.ui-datepicker-current,.ibo-is-secondary.ui-datepicker-close.ui-datepicker-current,.ui-dialog .ui-datepicker-close.ui-datepicker-current.ui-button,.ui-datepicker-close.ui-datepicker-current,.ibo-is-secondary.ui-datepicker-close,.ui-datepicker-close,.ui-dialog .ibo-is-regular.ui-datepicker-close.ui-button,.ibo-is-regular.ui-datepicker-close.ui-datepicker-current,.ibo-is-regular.ui-datepicker-close,.ui-dialog .ibo-button.ibo-is-secondary.ui-button,.ui-dialog .ibo-button.ui-button,.ui-dialog .ibo-button.ui-button.ui-datepicker-current,.ui-dialog .ibo-button.ui-button.ui-datepicker-close,.ibo-button.ibo-is-secondary.ui-datepicker-current,.ui-dialog .ibo-button.ui-datepicker-current.ui-button,.ibo-button.ui-datepicker-current,.ibo-button.ui-datepicker-current.ui-datepicker-close,.ibo-button.ibo-is-secondary.ui-datepicker-close,.ui-dialog .ibo-button.ui-datepicker-close.ui-button,.ibo-button.ui-datepicker-close.ui-datepicker-current,.ibo-button.ui-datepicker-close,.ui-dialog .ibo-button.ibo-is-regular.ui-button,.ibo-button.ibo-is-regular.ui-datepicker-current,.ibo-button.ibo-is-regular.ui-datepicker-close{background-color:#f8f9fa;color:#212934;box-shadow:0px 2px 0px #d5dde5}.ibo-button.ibo-is-regular.ibo-is-secondary:hover,.ui-dialog .ibo-is-regular.ibo-is-secondary.ui-button:hover,.ui-dialog .ibo-is-secondary.ui-button:hover,.ui-dialog .ui-button:hover,.ui-dialog .ui-button.ui-datepicker-current:hover,.ui-dialog .ui-button.ui-datepicker-close:hover,.ui-dialog .ibo-is-secondary.ui-button.ui-datepicker-current:hover,.ui-dialog .ui-button.ui-datepicker-current.ui-datepicker-close:hover,.ui-dialog .ibo-is-secondary.ui-button.ui-datepicker-close:hover,.ui-dialog .ui-button.ui-datepicker-close.ui-datepicker-current:hover,.ui-dialog .ibo-is-regular.ui-button:hover,.ui-dialog .ibo-is-regular.ui-button.ui-datepicker-current:hover,.ui-dialog .ibo-is-regular.ui-button.ui-datepicker-close:hover,.ibo-is-regular.ibo-is-secondary.ui-datepicker-current:hover,.ui-dialog .ibo-is-secondary.ui-datepicker-current.ui-button:hover,.ui-dialog .ui-datepicker-current.ui-button:hover,.ui-dialog .ui-datepicker-current.ui-button.ui-datepicker-close:hover,.ibo-is-secondary.ui-datepicker-current:hover,.ui-datepicker-current:hover,.ui-datepicker-current.ui-datepicker-close:hover,.ibo-is-secondary.ui-datepicker-current.ui-datepicker-close:hover,.ui-dialog .ui-datepicker-current.ui-datepicker-close.ui-button:hover,.ui-dialog .ibo-is-regular.ui-datepicker-current.ui-button:hover,.ibo-is-regular.ui-datepicker-current:hover,.ibo-is-regular.ui-datepicker-current.ui-datepicker-close:hover,.ibo-is-regular.ibo-is-secondary.ui-datepicker-close:hover,.ui-dialog .ibo-is-secondary.ui-datepicker-close.ui-button:hover,.ui-dialog .ui-datepicker-close.ui-button:hover,.ui-dialog .ui-datepicker-close.ui-button.ui-datepicker-current:hover,.ibo-is-secondary.ui-datepicker-close.ui-datepicker-current:hover,.ui-dialog .ui-datepicker-close.ui-datepicker-current.ui-button:hover,.ui-datepicker-close.ui-datepicker-current:hover,.ibo-is-secondary.ui-datepicker-close:hover,.ui-datepicker-close:hover,.ui-dialog .ibo-is-regular.ui-datepicker-close.ui-button:hover,.ibo-is-regular.ui-datepicker-close.ui-datepicker-current:hover,.ibo-is-regular.ui-datepicker-close:hover,.ui-dialog .ibo-button.ibo-is-secondary.ui-button:hover,.ui-dialog .ibo-button.ui-button:hover,.ui-dialog .ibo-button.ui-button.ui-datepicker-current:hover,.ui-dialog .ibo-button.ui-button.ui-datepicker-close:hover,.ibo-button.ibo-is-secondary.ui-datepicker-current:hover,.ui-dialog .ibo-button.ui-datepicker-current.ui-button:hover,.ibo-button.ui-datepicker-current:hover,.ibo-button.ui-datepicker-current.ui-datepicker-close:hover,.ibo-button.ibo-is-secondary.ui-datepicker-close:hover,.ui-dialog .ibo-button.ui-datepicker-close.ui-button:hover,.ibo-button.ui-datepicker-close.ui-datepicker-current:hover,.ibo-button.ui-datepicker-close:hover,.ui-dialog .ibo-button.ibo-is-regular.ui-button:hover,.ibo-button.ibo-is-regular.ui-datepicker-current:hover,.ibo-button.ibo-is-regular.ui-datepicker-close:hover{background-color:#e1e7ec;color:#212934;box-shadow:0px 2px 0px #d5dde5}.ibo-button.ibo-is-regular.ibo-is-secondary:active,.ui-dialog .ibo-is-regular.ibo-is-secondary.ui-button:active,.ui-dialog .ibo-is-secondary.ui-button:active,.ui-dialog .ui-button:active,.ui-dialog .ui-button.ui-datepicker-current:active,.ui-dialog .ui-button.ui-datepicker-close:active,.ui-dialog .ibo-is-secondary.ui-button.ui-datepicker-current:active,.ui-dialog .ui-button.ui-datepicker-current.ui-datepicker-close:active,.ui-dialog .ibo-is-secondary.ui-button.ui-datepicker-close:active,.ui-dialog .ui-button.ui-datepicker-close.ui-datepicker-current:active,.ui-dialog .ibo-is-regular.ui-button:active,.ui-dialog .ibo-is-regular.ui-button.ui-datepicker-current:active,.ui-dialog .ibo-is-regular.ui-button.ui-datepicker-close:active,.ibo-is-regular.ibo-is-secondary.ui-datepicker-current:active,.ui-dialog .ibo-is-secondary.ui-datepicker-current.ui-button:active,.ui-dialog .ui-datepicker-current.ui-button:active,.ui-dialog .ui-datepicker-current.ui-button.ui-datepicker-close:active,.ibo-is-secondary.ui-datepicker-current:active,.ui-datepicker-current:active,.ui-datepicker-current.ui-datepicker-close:active,.ibo-is-secondary.ui-datepicker-current.ui-datepicker-close:active,.ui-dialog .ui-datepicker-current.ui-datepicker-close.ui-button:active,.ui-dialog .ibo-is-regular.ui-datepicker-current.ui-button:active,.ibo-is-regular.ui-datepicker-current:active,.ibo-is-regular.ui-datepicker-current.ui-datepicker-close:active,.ibo-is-regular.ibo-is-secondary.ui-datepicker-close:active,.ui-dialog .ibo-is-secondary.ui-datepicker-close.ui-button:active,.ui-dialog .ui-datepicker-close.ui-button:active,.ui-dialog .ui-datepicker-close.ui-button.ui-datepicker-current:active,.ibo-is-secondary.ui-datepicker-close.ui-datepicker-current:active,.ui-dialog .ui-datepicker-close.ui-datepicker-current.ui-button:active,.ui-datepicker-close.ui-datepicker-current:active,.ibo-is-secondary.ui-datepicker-close:active,.ui-datepicker-close:active,.ui-dialog .ibo-is-regular.ui-datepicker-close.ui-button:active,.ibo-is-regular.ui-datepicker-close.ui-datepicker-current:active,.ibo-is-regular.ui-datepicker-close:active,.ui-dialog .ibo-button.ibo-is-secondary.ui-button:active,.ui-dialog .ibo-button.ui-button:active,.ui-dialog .ibo-button.ui-button.ui-datepicker-current:active,.ui-dialog .ibo-button.ui-button.ui-datepicker-close:active,.ibo-button.ibo-is-secondary.ui-datepicker-current:active,.ui-dialog .ibo-button.ui-datepicker-current.ui-button:active,.ibo-button.ui-datepicker-current:active,.ibo-button.ui-datepicker-current.ui-datepicker-close:active,.ibo-button.ibo-is-secondary.ui-datepicker-close:active,.ui-dialog .ibo-button.ui-datepicker-close.ui-button:active,.ibo-button.ui-datepicker-close.ui-datepicker-current:active,.ibo-button.ui-datepicker-close:active,.ui-dialog .ibo-button.ibo-is-regular.ui-button:active,.ibo-button.ibo-is-regular.ui-datepicker-current:active,.ibo-button.ibo-is-regular.ui-datepicker-close:active{background-color:#e1e7ec;color:#212934;box-shadow:inset 0px 2px 0px #d5dde5 , 0px 2px 0px #e1e7ec}.ibo-button.ibo-is-regular.ibo-is-secondary:disabled,.ui-dialog .ibo-is-regular.ibo-is-secondary.ui-button:disabled,.ui-dialog .ibo-is-secondary.ui-button:disabled,.ui-dialog .ui-button:disabled,.ui-dialog .ui-button.ui-datepicker-current:disabled,.ui-dialog .ui-button.ui-datepicker-close:disabled,.ui-dialog .ibo-is-secondary.ui-button.ui-datepicker-current:disabled,.ui-dialog .ui-button.ui-datepicker-current.ui-datepicker-close:disabled,.ui-dialog .ibo-is-secondary.ui-button.ui-datepicker-close:disabled,.ui-dialog .ui-button.ui-datepicker-close.ui-datepicker-current:disabled,.ui-dialog .ibo-is-regular.ui-button:disabled,.ui-dialog .ibo-is-regular.ui-button.ui-datepicker-current:disabled,.ui-dialog .ibo-is-regular.ui-button.ui-datepicker-close:disabled,.ibo-is-regular.ibo-is-secondary.ui-datepicker-current:disabled,.ui-dialog .ibo-is-secondary.ui-datepicker-current.ui-button:disabled,.ui-dialog .ui-datepicker-current.ui-button:disabled,.ui-dialog .ui-datepicker-current.ui-button.ui-datepicker-close:disabled,.ibo-is-secondary.ui-datepicker-current:disabled,.ui-datepicker-current:disabled,.ui-datepicker-current.ui-datepicker-close:disabled,.ibo-is-secondary.ui-datepicker-current.ui-datepicker-close:disabled,.ui-dialog .ui-datepicker-current.ui-datepicker-close.ui-button:disabled,.ui-dialog .ibo-is-regular.ui-datepicker-current.ui-button:disabled,.ibo-is-regular.ui-datepicker-current:disabled,.ibo-is-regular.ui-datepicker-current.ui-datepicker-close:disabled,.ibo-is-regular.ibo-is-secondary.ui-datepicker-close:disabled,.ui-dialog .ibo-is-secondary.ui-datepicker-close.ui-button:disabled,.ui-dialog .ui-datepicker-close.ui-button:disabled,.ui-dialog .ui-datepicker-close.ui-button.ui-datepicker-current:disabled,.ibo-is-secondary.ui-datepicker-close.ui-datepicker-current:disabled,.ui-dialog .ui-datepicker-close.ui-datepicker-current.ui-button:disabled,.ui-datepicker-close.ui-datepicker-current:disabled,.ibo-is-secondary.ui-datepicker-close:disabled,.ui-datepicker-close:disabled,.ui-dialog .ibo-is-regular.ui-datepicker-close.ui-button:disabled,.ibo-is-regular.ui-datepicker-close.ui-datepicker-current:disabled,.ibo-is-regular.ui-datepicker-close:disabled,.ui-dialog .ibo-button.ibo-is-secondary.ui-button:disabled,.ui-dialog .ibo-button.ui-button:disabled,.ui-dialog .ibo-button.ui-button.ui-datepicker-current:disabled,.ui-dialog .ibo-button.ui-button.ui-datepicker-close:disabled,.ibo-button.ibo-is-secondary.ui-datepicker-current:disabled,.ui-dialog .ibo-button.ui-datepicker-current.ui-button:disabled,.ibo-button.ui-datepicker-current:disabled,.ibo-button.ui-datepicker-current.ui-datepicker-close:disabled,.ibo-button.ibo-is-secondary.ui-datepicker-close:disabled,.ui-dialog .ibo-button.ui-datepicker-close.ui-button:disabled,.ibo-button.ui-datepicker-close.ui-datepicker-current:disabled,.ibo-button.ui-datepicker-close:disabled,.ui-dialog .ibo-button.ibo-is-regular.ui-button:disabled,.ibo-button.ibo-is-regular.ui-datepicker-current:disabled,.ibo-button.ibo-is-regular.ui-datepicker-close:disabled{background-color:#d5dde5;color:#6e7a8a;box-shadow:inset 0px 2px 0px #d5dde5}.ibo-button.ibo-is-regular.ibo-is-danger,.ui-dialog .ibo-is-regular.ibo-is-danger.ui-button,.ui-dialog .ibo-is-danger.ui-button,.ui-dialog .ibo-is-danger.ui-button.ui-datepicker-current,.ui-dialog .ibo-is-danger.ui-button.ui-datepicker-close,.ibo-is-regular.ibo-is-danger.ui-datepicker-current,.ui-dialog .ibo-is-danger.ui-datepicker-current.ui-button,.ibo-is-danger.ui-datepicker-current,.ibo-is-danger.ui-datepicker-current.ui-datepicker-close,.ibo-is-regular.ibo-is-danger.ui-datepicker-close,.ui-dialog .ibo-is-danger.ui-datepicker-close.ui-button,.ibo-is-danger.ui-datepicker-close.ui-datepicker-current,.ibo-is-danger.ui-datepicker-close,.ui-dialog .ibo-button.ibo-is-danger.ui-button,.ibo-button.ibo-is-danger.ui-datepicker-current,.ibo-button.ibo-is-danger.ui-datepicker-close{background-color:#c53030;color:white;box-shadow:0px 2px 0px #742a2a}.ibo-button.ibo-is-regular.ibo-is-danger:hover,.ui-dialog .ibo-is-regular.ibo-is-danger.ui-button:hover,.ui-dialog .ibo-is-danger.ui-button:hover,.ui-dialog .ibo-is-danger.ui-button.ui-datepicker-current:hover,.ui-dialog .ibo-is-danger.ui-button.ui-datepicker-close:hover,.ibo-is-regular.ibo-is-danger.ui-datepicker-current:hover,.ui-dialog .ibo-is-danger.ui-datepicker-current.ui-button:hover,.ibo-is-danger.ui-datepicker-current:hover,.ibo-is-danger.ui-datepicker-current.ui-datepicker-close:hover,.ibo-is-regular.ibo-is-danger.ui-datepicker-close:hover,.ui-dialog .ibo-is-danger.ui-datepicker-close.ui-button:hover,.ibo-is-danger.ui-datepicker-close.ui-datepicker-current:hover,.ibo-is-danger.ui-datepicker-close:hover,.ui-dialog .ibo-button.ibo-is-danger.ui-button:hover,.ibo-button.ibo-is-danger.ui-datepicker-current:hover,.ibo-button.ibo-is-danger.ui-datepicker-close:hover{background-color:#9b2c2c;color:white;box-shadow:0px 2px 0px #742a2a}.ibo-button.ibo-is-regular.ibo-is-danger:active,.ui-dialog .ibo-is-regular.ibo-is-danger.ui-button:active,.ui-dialog .ibo-is-danger.ui-button:active,.ui-dialog .ibo-is-danger.ui-button.ui-datepicker-current:active,.ui-dialog .ibo-is-danger.ui-button.ui-datepicker-close:active,.ibo-is-regular.ibo-is-danger.ui-datepicker-current:active,.ui-dialog .ibo-is-danger.ui-datepicker-current.ui-button:active,.ibo-is-danger.ui-datepicker-current:active,.ibo-is-danger.ui-datepicker-current.ui-datepicker-close:active,.ibo-is-regular.ibo-is-danger.ui-datepicker-close:active,.ui-dialog .ibo-is-danger.ui-datepicker-close.ui-button:active,.ibo-is-danger.ui-datepicker-close.ui-datepicker-current:active,.ibo-is-danger.ui-datepicker-close:active,.ui-dialog .ibo-button.ibo-is-danger.ui-button:active,.ibo-button.ibo-is-danger.ui-datepicker-current:active,.ibo-button.ibo-is-danger.ui-datepicker-close:active{background-color:#9b2c2c;color:white;box-shadow:inset 0px 2px 0px #742a2a , 0px 2px 0px #9b2c2c}.ibo-button.ibo-is-regular.ibo-is-danger:disabled,.ui-dialog .ibo-is-regular.ibo-is-danger.ui-button:disabled,.ui-dialog .ibo-is-danger.ui-button:disabled,.ui-dialog .ibo-is-danger.ui-button.ui-datepicker-current:disabled,.ui-dialog .ibo-is-danger.ui-button.ui-datepicker-close:disabled,.ibo-is-regular.ibo-is-danger.ui-datepicker-current:disabled,.ui-dialog .ibo-is-danger.ui-datepicker-current.ui-button:disabled,.ibo-is-danger.ui-datepicker-current:disabled,.ibo-is-danger.ui-datepicker-current.ui-datepicker-close:disabled,.ibo-is-regular.ibo-is-danger.ui-datepicker-close:disabled,.ui-dialog .ibo-is-danger.ui-datepicker-close.ui-button:disabled,.ibo-is-danger.ui-datepicker-close.ui-datepicker-current:disabled,.ibo-is-danger.ui-datepicker-close:disabled,.ui-dialog .ibo-button.ibo-is-danger.ui-button:disabled,.ibo-button.ibo-is-danger.ui-datepicker-current:disabled,.ibo-button.ibo-is-danger.ui-datepicker-close:disabled{background-color:#d5dde5;color:#6e7a8a;box-shadow:inset 0px 2px 0px #d5dde5}.ibo-button.ibo-is-regular.ibo-is-success,.ui-dialog .ibo-is-regular.ibo-is-success.ui-button,.ui-dialog .ibo-is-success.ui-button,.ui-dialog .ibo-is-success.ui-button.ui-datepicker-current,.ui-dialog .ibo-is-success.ui-button.ui-datepicker-close,.ibo-is-regular.ibo-is-success.ui-datepicker-current,.ui-dialog .ibo-is-success.ui-datepicker-current.ui-button,.ibo-is-success.ui-datepicker-current,.ibo-is-success.ui-datepicker-current.ui-datepicker-close,.ibo-is-regular.ibo-is-success.ui-datepicker-close,.ui-dialog .ibo-is-success.ui-datepicker-close.ui-button,.ibo-is-success.ui-datepicker-close.ui-datepicker-current,.ibo-is-success.ui-datepicker-close,.ui-dialog .ibo-button.ibo-is-success.ui-button,.ibo-button.ibo-is-success.ui-datepicker-current,.ibo-button.ibo-is-success.ui-datepicker-close{background-color:#558b2f;color:white;box-shadow:0px 2px 0px #235816}.ibo-button.ibo-is-regular.ibo-is-success:hover,.ui-dialog .ibo-is-regular.ibo-is-success.ui-button:hover,.ui-dialog .ibo-is-success.ui-button:hover,.ui-dialog .ibo-is-success.ui-button.ui-datepicker-current:hover,.ui-dialog .ibo-is-success.ui-button.ui-datepicker-close:hover,.ibo-is-regular.ibo-is-success.ui-datepicker-current:hover,.ui-dialog .ibo-is-success.ui-datepicker-current.ui-button:hover,.ibo-is-success.ui-datepicker-current:hover,.ibo-is-success.ui-datepicker-current.ui-datepicker-close:hover,.ibo-is-regular.ibo-is-success.ui-datepicker-close:hover,.ui-dialog .ibo-is-success.ui-datepicker-close.ui-button:hover,.ibo-is-success.ui-datepicker-close.ui-datepicker-current:hover,.ibo-is-success.ui-datepicker-close:hover,.ui-dialog .ibo-button.ibo-is-success.ui-button:hover,.ibo-button.ibo-is-success.ui-datepicker-current:hover,.ibo-button.ibo-is-success.ui-datepicker-close:hover{background-color:#33691e;color:white;box-shadow:0px 2px 0px #235816}.ibo-button.ibo-is-regular.ibo-is-success:active,.ui-dialog .ibo-is-regular.ibo-is-success.ui-button:active,.ui-dialog .ibo-is-success.ui-button:active,.ui-dialog .ibo-is-success.ui-button.ui-datepicker-current:active,.ui-dialog .ibo-is-success.ui-button.ui-datepicker-close:active,.ibo-is-regular.ibo-is-success.ui-datepicker-current:active,.ui-dialog .ibo-is-success.ui-datepicker-current.ui-button:active,.ibo-is-success.ui-datepicker-current:active,.ibo-is-success.ui-datepicker-current.ui-datepicker-close:active,.ibo-is-regular.ibo-is-success.ui-datepicker-close:active,.ui-dialog .ibo-is-success.ui-datepicker-close.ui-button:active,.ibo-is-success.ui-datepicker-close.ui-datepicker-current:active,.ibo-is-success.ui-datepicker-close:active,.ui-dialog .ibo-button.ibo-is-success.ui-button:active,.ibo-button.ibo-is-success.ui-datepicker-current:active,.ibo-button.ibo-is-success.ui-datepicker-close:active{background-color:#33691e;color:white;box-shadow:inset 0px 2px 0px #235816 , 0px 2px 0px #33691e}.ibo-button.ibo-is-regular.ibo-is-success:disabled,.ui-dialog .ibo-is-regular.ibo-is-success.ui-button:disabled,.ui-dialog .ibo-is-success.ui-button:disabled,.ui-dialog .ibo-is-success.ui-button.ui-datepicker-current:disabled,.ui-dialog .ibo-is-success.ui-button.ui-datepicker-close:disabled,.ibo-is-regular.ibo-is-success.ui-datepicker-current:disabled,.ui-dialog .ibo-is-success.ui-datepicker-current.ui-button:disabled,.ibo-is-success.ui-datepicker-current:disabled,.ibo-is-success.ui-datepicker-current.ui-datepicker-close:disabled,.ibo-is-regular.ibo-is-success.ui-datepicker-close:disabled,.ui-dialog .ibo-is-success.ui-datepicker-close.ui-button:disabled,.ibo-is-success.ui-datepicker-close.ui-datepicker-current:disabled,.ibo-is-success.ui-datepicker-close:disabled,.ui-dialog .ibo-button.ibo-is-success.ui-button:disabled,.ibo-button.ibo-is-success.ui-datepicker-current:disabled,.ibo-button.ibo-is-success.ui-datepicker-close:disabled{background-color:#d5dde5;color:#6e7a8a;box-shadow:inset 0px 2px 0px #d5dde5}.ibo-button.ibo-is-regular.ibo-is-red,.ui-dialog .ibo-is-regular.ibo-is-red.ui-button,.ui-dialog .ibo-is-red.ui-button,.ui-dialog .ibo-is-red.ui-button.ui-datepicker-current,.ui-dialog .ibo-is-red.ui-button.ui-datepicker-close,.ibo-is-regular.ibo-is-red.ui-datepicker-current,.ui-dialog .ibo-is-red.ui-datepicker-current.ui-button,.ibo-is-red.ui-datepicker-current,.ibo-is-red.ui-datepicker-current.ui-datepicker-close,.ibo-is-regular.ibo-is-red.ui-datepicker-close,.ui-dialog .ibo-is-red.ui-datepicker-close.ui-button,.ibo-is-red.ui-datepicker-close.ui-datepicker-current,.ibo-is-red.ui-datepicker-close,.ui-dialog .ibo-button.ibo-is-red.ui-button,.ibo-button.ibo-is-red.ui-datepicker-current,.ibo-button.ibo-is-red.ui-datepicker-close{background-color:#c53030;color:white;box-shadow:0px 2px 0px #742a2a}.ibo-button.ibo-is-regular.ibo-is-red:hover,.ui-dialog .ibo-is-regular.ibo-is-red.ui-button:hover,.ui-dialog .ibo-is-red.ui-button:hover,.ui-dialog .ibo-is-red.ui-button.ui-datepicker-current:hover,.ui-dialog .ibo-is-red.ui-button.ui-datepicker-close:hover,.ibo-is-regular.ibo-is-red.ui-datepicker-current:hover,.ui-dialog .ibo-is-red.ui-datepicker-current.ui-button:hover,.ibo-is-red.ui-datepicker-current:hover,.ibo-is-red.ui-datepicker-current.ui-datepicker-close:hover,.ibo-is-regular.ibo-is-red.ui-datepicker-close:hover,.ui-dialog .ibo-is-red.ui-datepicker-close.ui-button:hover,.ibo-is-red.ui-datepicker-close.ui-datepicker-current:hover,.ibo-is-red.ui-datepicker-close:hover,.ui-dialog .ibo-button.ibo-is-red.ui-button:hover,.ibo-button.ibo-is-red.ui-datepicker-current:hover,.ibo-button.ibo-is-red.ui-datepicker-close:hover{background-color:#9b2c2c;color:white;box-shadow:0px 2px 0px #742a2a}.ibo-button.ibo-is-regular.ibo-is-red:active,.ui-dialog .ibo-is-regular.ibo-is-red.ui-button:active,.ui-dialog .ibo-is-red.ui-button:active,.ui-dialog .ibo-is-red.ui-button.ui-datepicker-current:active,.ui-dialog .ibo-is-red.ui-button.ui-datepicker-close:active,.ibo-is-regular.ibo-is-red.ui-datepicker-current:active,.ui-dialog .ibo-is-red.ui-datepicker-current.ui-button:active,.ibo-is-red.ui-datepicker-current:active,.ibo-is-red.ui-datepicker-current.ui-datepicker-close:active,.ibo-is-regular.ibo-is-red.ui-datepicker-close:active,.ui-dialog .ibo-is-red.ui-datepicker-close.ui-button:active,.ibo-is-red.ui-datepicker-close.ui-datepicker-current:active,.ibo-is-red.ui-datepicker-close:active,.ui-dialog .ibo-button.ibo-is-red.ui-button:active,.ibo-button.ibo-is-red.ui-datepicker-current:active,.ibo-button.ibo-is-red.ui-datepicker-close:active{background-color:#9b2c2c;color:white;box-shadow:inset 0px 2px 0px #742a2a , 0px 2px 0px #9b2c2c}.ibo-button.ibo-is-regular.ibo-is-red:disabled,.ui-dialog .ibo-is-regular.ibo-is-red.ui-button:disabled,.ui-dialog .ibo-is-red.ui-button:disabled,.ui-dialog .ibo-is-red.ui-button.ui-datepicker-current:disabled,.ui-dialog .ibo-is-red.ui-button.ui-datepicker-close:disabled,.ibo-is-regular.ibo-is-red.ui-datepicker-current:disabled,.ui-dialog .ibo-is-red.ui-datepicker-current.ui-button:disabled,.ibo-is-red.ui-datepicker-current:disabled,.ibo-is-red.ui-datepicker-current.ui-datepicker-close:disabled,.ibo-is-regular.ibo-is-red.ui-datepicker-close:disabled,.ui-dialog .ibo-is-red.ui-datepicker-close.ui-button:disabled,.ibo-is-red.ui-datepicker-close.ui-datepicker-current:disabled,.ibo-is-red.ui-datepicker-close:disabled,.ui-dialog .ibo-button.ibo-is-red.ui-button:disabled,.ibo-button.ibo-is-red.ui-datepicker-current:disabled,.ibo-button.ibo-is-red.ui-datepicker-close:disabled{background-color:#d5dde5;color:#6e7a8a;box-shadow:inset 0px 2px 0px #d5dde5}.ibo-button.ibo-is-regular.ibo-is-green,.ui-dialog .ibo-is-regular.ibo-is-green.ui-button,.ui-dialog .ibo-is-green.ui-button,.ui-dialog .ibo-is-green.ui-button.ui-datepicker-current,.ui-dialog .ibo-is-green.ui-button.ui-datepicker-close,.ibo-is-regular.ibo-is-green.ui-datepicker-current,.ui-dialog .ibo-is-green.ui-datepicker-current.ui-button,.ibo-is-green.ui-datepicker-current,.ibo-is-green.ui-datepicker-current.ui-datepicker-close,.ibo-is-regular.ibo-is-green.ui-datepicker-close,.ui-dialog .ibo-is-green.ui-datepicker-close.ui-button,.ibo-is-green.ui-datepicker-close.ui-datepicker-current,.ibo-is-green.ui-datepicker-close,.ui-dialog .ibo-button.ibo-is-green.ui-button,.ibo-button.ibo-is-green.ui-datepicker-current,.ibo-button.ibo-is-green.ui-datepicker-close{background-color:#558b2f;color:white;box-shadow:0px 2px 0px #235816}.ibo-button.ibo-is-regular.ibo-is-green:hover,.ui-dialog .ibo-is-regular.ibo-is-green.ui-button:hover,.ui-dialog .ibo-is-green.ui-button:hover,.ui-dialog .ibo-is-green.ui-button.ui-datepicker-current:hover,.ui-dialog .ibo-is-green.ui-button.ui-datepicker-close:hover,.ibo-is-regular.ibo-is-green.ui-datepicker-current:hover,.ui-dialog .ibo-is-green.ui-datepicker-current.ui-button:hover,.ibo-is-green.ui-datepicker-current:hover,.ibo-is-green.ui-datepicker-current.ui-datepicker-close:hover,.ibo-is-regular.ibo-is-green.ui-datepicker-close:hover,.ui-dialog .ibo-is-green.ui-datepicker-close.ui-button:hover,.ibo-is-green.ui-datepicker-close.ui-datepicker-current:hover,.ibo-is-green.ui-datepicker-close:hover,.ui-dialog .ibo-button.ibo-is-green.ui-button:hover,.ibo-button.ibo-is-green.ui-datepicker-current:hover,.ibo-button.ibo-is-green.ui-datepicker-close:hover{background-color:#33691e;color:white;box-shadow:0px 2px 0px #235816}.ibo-button.ibo-is-regular.ibo-is-green:active,.ui-dialog .ibo-is-regular.ibo-is-green.ui-button:active,.ui-dialog .ibo-is-green.ui-button:active,.ui-dialog .ibo-is-green.ui-button.ui-datepicker-current:active,.ui-dialog .ibo-is-green.ui-button.ui-datepicker-close:active,.ibo-is-regular.ibo-is-green.ui-datepicker-current:active,.ui-dialog .ibo-is-green.ui-datepicker-current.ui-button:active,.ibo-is-green.ui-datepicker-current:active,.ibo-is-green.ui-datepicker-current.ui-datepicker-close:active,.ibo-is-regular.ibo-is-green.ui-datepicker-close:active,.ui-dialog .ibo-is-green.ui-datepicker-close.ui-button:active,.ibo-is-green.ui-datepicker-close.ui-datepicker-current:active,.ibo-is-green.ui-datepicker-close:active,.ui-dialog .ibo-button.ibo-is-green.ui-button:active,.ibo-button.ibo-is-green.ui-datepicker-current:active,.ibo-button.ibo-is-green.ui-datepicker-close:active{background-color:#33691e;color:white;box-shadow:inset 0px 2px 0px #235816 , 0px 2px 0px #33691e}.ibo-button.ibo-is-regular.ibo-is-green:disabled,.ui-dialog .ibo-is-regular.ibo-is-green.ui-button:disabled,.ui-dialog .ibo-is-green.ui-button:disabled,.ui-dialog .ibo-is-green.ui-button.ui-datepicker-current:disabled,.ui-dialog .ibo-is-green.ui-button.ui-datepicker-close:disabled,.ibo-is-regular.ibo-is-green.ui-datepicker-current:disabled,.ui-dialog .ibo-is-green.ui-datepicker-current.ui-button:disabled,.ibo-is-green.ui-datepicker-current:disabled,.ibo-is-green.ui-datepicker-current.ui-datepicker-close:disabled,.ibo-is-regular.ibo-is-green.ui-datepicker-close:disabled,.ui-dialog .ibo-is-green.ui-datepicker-close.ui-button:disabled,.ibo-is-green.ui-datepicker-close.ui-datepicker-current:disabled,.ibo-is-green.ui-datepicker-close:disabled,.ui-dialog .ibo-button.ibo-is-green.ui-button:disabled,.ibo-button.ibo-is-green.ui-datepicker-current:disabled,.ibo-button.ibo-is-green.ui-datepicker-close:disabled{background-color:#d5dde5;color:#6e7a8a;box-shadow:inset 0px 2px 0px #d5dde5}.ibo-button.ibo-is-regular.ibo-is-cyan,.ui-dialog .ibo-is-regular.ibo-is-cyan.ui-button,.ui-dialog .ibo-is-cyan.ui-button,.ui-dialog .ibo-is-cyan.ui-button.ui-datepicker-current,.ui-dialog .ibo-is-cyan.ui-button.ui-datepicker-close,.ibo-is-regular.ibo-is-cyan.ui-datepicker-current,.ui-dialog .ibo-is-cyan.ui-datepicker-current.ui-button,.ibo-is-cyan.ui-datepicker-current,.ibo-is-cyan.ui-datepicker-current.ui-datepicker-close,.ibo-is-regular.ibo-is-cyan.ui-datepicker-close,.ui-dialog .ibo-is-cyan.ui-datepicker-close.ui-button,.ibo-is-cyan.ui-datepicker-close.ui-datepicker-current,.ibo-is-cyan.ui-datepicker-close,.ui-dialog .ibo-button.ibo-is-cyan.ui-button,.ibo-button.ibo-is-cyan.ui-datepicker-current,.ibo-button.ibo-is-cyan.ui-datepicker-close{background-color:#00838f;color:white;box-shadow:0px 2px 0px #003636}.ibo-button.ibo-is-regular.ibo-is-cyan:hover,.ui-dialog .ibo-is-regular.ibo-is-cyan.ui-button:hover,.ui-dialog .ibo-is-cyan.ui-button:hover,.ui-dialog .ibo-is-cyan.ui-button.ui-datepicker-current:hover,.ui-dialog .ibo-is-cyan.ui-button.ui-datepicker-close:hover,.ibo-is-regular.ibo-is-cyan.ui-datepicker-current:hover,.ui-dialog .ibo-is-cyan.ui-datepicker-current.ui-button:hover,.ibo-is-cyan.ui-datepicker-current:hover,.ibo-is-cyan.ui-datepicker-current.ui-datepicker-close:hover,.ibo-is-regular.ibo-is-cyan.ui-datepicker-close:hover,.ui-dialog .ibo-is-cyan.ui-datepicker-close.ui-button:hover,.ibo-is-cyan.ui-datepicker-close.ui-datepicker-current:hover,.ibo-is-cyan.ui-datepicker-close:hover,.ui-dialog .ibo-button.ibo-is-cyan.ui-button:hover,.ibo-button.ibo-is-cyan.ui-datepicker-current:hover,.ibo-button.ibo-is-cyan.ui-datepicker-close:hover{background-color:#006164;color:white;box-shadow:0px 2px 0px #003636}.ibo-button.ibo-is-regular.ibo-is-cyan:active,.ui-dialog .ibo-is-regular.ibo-is-cyan.ui-button:active,.ui-dialog .ibo-is-cyan.ui-button:active,.ui-dialog .ibo-is-cyan.ui-button.ui-datepicker-current:active,.ui-dialog .ibo-is-cyan.ui-button.ui-datepicker-close:active,.ibo-is-regular.ibo-is-cyan.ui-datepicker-current:active,.ui-dialog .ibo-is-cyan.ui-datepicker-current.ui-button:active,.ibo-is-cyan.ui-datepicker-current:active,.ibo-is-cyan.ui-datepicker-current.ui-datepicker-close:active,.ibo-is-regular.ibo-is-cyan.ui-datepicker-close:active,.ui-dialog .ibo-is-cyan.ui-datepicker-close.ui-button:active,.ibo-is-cyan.ui-datepicker-close.ui-datepicker-current:active,.ibo-is-cyan.ui-datepicker-close:active,.ui-dialog .ibo-button.ibo-is-cyan.ui-button:active,.ibo-button.ibo-is-cyan.ui-datepicker-current:active,.ibo-button.ibo-is-cyan.ui-datepicker-close:active{background-color:#006164;color:white;box-shadow:inset 0px 2px 0px #003636 , 0px 2px 0px #006164}.ibo-button.ibo-is-regular.ibo-is-cyan:disabled,.ui-dialog .ibo-is-regular.ibo-is-cyan.ui-button:disabled,.ui-dialog .ibo-is-cyan.ui-button:disabled,.ui-dialog .ibo-is-cyan.ui-button.ui-datepicker-current:disabled,.ui-dialog .ibo-is-cyan.ui-button.ui-datepicker-close:disabled,.ibo-is-regular.ibo-is-cyan.ui-datepicker-current:disabled,.ui-dialog .ibo-is-cyan.ui-datepicker-current.ui-button:disabled,.ibo-is-cyan.ui-datepicker-current:disabled,.ibo-is-cyan.ui-datepicker-current.ui-datepicker-close:disabled,.ibo-is-regular.ibo-is-cyan.ui-datepicker-close:disabled,.ui-dialog .ibo-is-cyan.ui-datepicker-close.ui-button:disabled,.ibo-is-cyan.ui-datepicker-close.ui-datepicker-current:disabled,.ibo-is-cyan.ui-datepicker-close:disabled,.ui-dialog .ibo-button.ibo-is-cyan.ui-button:disabled,.ibo-button.ibo-is-cyan.ui-datepicker-current:disabled,.ibo-button.ibo-is-cyan.ui-datepicker-close:disabled{background-color:#d5dde5;color:#6e7a8a;box-shadow:inset 0px 2px 0px #d5dde5}.ibo-button.ibo-is-alternative.ibo-is-neutral,.ui-dialog .ibo-is-alternative.ibo-is-neutral.ui-button,.ui-dialog .ibo-is-neutral.ui-button.ui-dialog-titlebar-close,.ui-dialog .ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-is-alternative.ui-button.ui-dialog-titlebar-close,.ibo-is-alternative.ibo-is-neutral.ui-datepicker-current,.ui-dialog .ibo-is-neutral.ui-datepicker-current.ui-button.ui-dialog-titlebar-close,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-is-alternative.ui-datepicker-current.ui-button.ui-dialog-titlebar-close,.ibo-is-alternative.ibo-is-neutral.ui-datepicker-close,.ui-dialog .ibo-is-neutral.ui-datepicker-close.ui-button.ui-dialog-titlebar-close,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-is-alternative.ui-datepicker-close.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-button.ibo-is-neutral.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-is-neutral.ui-button.ui-dialog-titlebar-close.ui-datepicker-current,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current,.ui-dialog .ibo-is-neutral.ui-button.ui-dialog-titlebar-close.ui-datepicker-close,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-button.ibo-is-alternative.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-is-alternative.ui-button.ui-dialog-titlebar-close.ui-datepicker-current,.ui-dialog .ibo-is-alternative.ui-button.ui-dialog-titlebar-close.ui-datepicker-close{background-color:transparent;color:#212934;box-shadow:0px 2px 0px transparent}.ibo-button.ibo-is-alternative.ibo-is-neutral:hover,.ui-dialog .ibo-is-alternative.ibo-is-neutral.ui-button:hover,.ui-dialog .ibo-is-neutral.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-is-alternative.ui-button.ui-dialog-titlebar-close:hover,.ibo-is-alternative.ibo-is-neutral.ui-datepicker-current:hover,.ui-dialog .ibo-is-neutral.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-is-alternative.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:hover,.ibo-is-alternative.ibo-is-neutral.ui-datepicker-close:hover,.ui-dialog .ibo-is-neutral.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-is-alternative.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-button.ibo-is-neutral.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-is-neutral.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:hover,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current:hover,.ui-dialog .ibo-is-neutral.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:hover,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close:hover,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-button.ibo-is-alternative.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-is-alternative.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:hover,.ui-dialog .ibo-is-alternative.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:hover{background-color:#f8f9fa;color:#212934;box-shadow:0px 2px 0px #f8f9fa}.ibo-button.ibo-is-alternative.ibo-is-neutral:active,.ui-dialog .ibo-is-alternative.ibo-is-neutral.ui-button:active,.ui-dialog .ibo-is-neutral.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-is-alternative.ui-button.ui-dialog-titlebar-close:active,.ibo-is-alternative.ibo-is-neutral.ui-datepicker-current:active,.ui-dialog .ibo-is-neutral.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-is-alternative.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:active,.ibo-is-alternative.ibo-is-neutral.ui-datepicker-close:active,.ui-dialog .ibo-is-neutral.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-is-alternative.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-button.ibo-is-neutral.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-is-neutral.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:active,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current:active,.ui-dialog .ibo-is-neutral.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:active,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close:active,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-button.ibo-is-alternative.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-is-alternative.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:active,.ui-dialog .ibo-is-alternative.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:active{background-color:#f8f9fa;color:#212934;box-shadow:inset 0px 2px 0px #e1e7ec , 0px 2px 0px #f8f9fa}.ibo-button.ibo-is-alternative.ibo-is-neutral:disabled,.ui-dialog .ibo-is-alternative.ibo-is-neutral.ui-button:disabled,.ui-dialog .ibo-is-neutral.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-is-alternative.ui-button.ui-dialog-titlebar-close:disabled,.ibo-is-alternative.ibo-is-neutral.ui-datepicker-current:disabled,.ui-dialog .ibo-is-neutral.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-is-alternative.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:disabled,.ibo-is-alternative.ibo-is-neutral.ui-datepicker-close:disabled,.ui-dialog .ibo-is-neutral.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-is-alternative.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-button.ibo-is-neutral.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-is-neutral.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:disabled,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current:disabled,.ui-dialog .ibo-is-neutral.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:disabled,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close:disabled,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-button.ibo-is-alternative.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-is-alternative.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:disabled,.ui-dialog .ibo-is-alternative.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:disabled{background-color:transparent;color:#929fb1;box-shadow:inset 0px 2px 0px transparent}.ibo-button.ibo-is-alternative.ibo-is-primary,.ui-dialog .ibo-is-alternative.ibo-is-primary.ui-button,.ui-dialog .ibo-is-primary.ui-button.ui-dialog-titlebar-close,.ibo-is-alternative.ibo-is-primary.ui-datepicker-current,.ui-dialog .ibo-is-primary.ui-datepicker-current.ui-button.ui-dialog-titlebar-close,.ibo-is-alternative.ibo-is-primary.ui-datepicker-close,.ui-dialog .ibo-is-primary.ui-datepicker-close.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-button.ibo-is-primary.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-is-primary.ui-button.ui-dialog-titlebar-close.ui-datepicker-current,.ui-dialog .ibo-is-primary.ui-button.ui-dialog-titlebar-close.ui-datepicker-close{background-color:transparent;color:#006164;box-shadow:0px 2px 0px transparent}.ibo-button.ibo-is-alternative.ibo-is-primary:hover,.ui-dialog .ibo-is-alternative.ibo-is-primary.ui-button:hover,.ui-dialog .ibo-is-primary.ui-button.ui-dialog-titlebar-close:hover,.ibo-is-alternative.ibo-is-primary.ui-datepicker-current:hover,.ui-dialog .ibo-is-primary.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:hover,.ibo-is-alternative.ibo-is-primary.ui-datepicker-close:hover,.ui-dialog .ibo-is-primary.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-button.ibo-is-primary.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-is-primary.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:hover,.ui-dialog .ibo-is-primary.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:hover{background-color:white;color:#212934;box-shadow:0px 2px 0px white}.ibo-button.ibo-is-alternative.ibo-is-primary:active,.ui-dialog .ibo-is-alternative.ibo-is-primary.ui-button:active,.ui-dialog .ibo-is-primary.ui-button.ui-dialog-titlebar-close:active,.ibo-is-alternative.ibo-is-primary.ui-datepicker-current:active,.ui-dialog .ibo-is-primary.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:active,.ibo-is-alternative.ibo-is-primary.ui-datepicker-close:active,.ui-dialog .ibo-is-primary.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-button.ibo-is-primary.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-is-primary.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:active,.ui-dialog .ibo-is-primary.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:active{background-color:white;color:#212934;box-shadow:inset 0px 2px 0px white , 0px 2px 0px white}.ibo-button.ibo-is-alternative.ibo-is-primary:disabled,.ui-dialog .ibo-is-alternative.ibo-is-primary.ui-button:disabled,.ui-dialog .ibo-is-primary.ui-button.ui-dialog-titlebar-close:disabled,.ibo-is-alternative.ibo-is-primary.ui-datepicker-current:disabled,.ui-dialog .ibo-is-primary.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:disabled,.ibo-is-alternative.ibo-is-primary.ui-datepicker-close:disabled,.ui-dialog .ibo-is-primary.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-button.ibo-is-primary.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-is-primary.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:disabled,.ui-dialog .ibo-is-primary.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:disabled{background-color:transparent;color:#929fb1;box-shadow:inset 0px 2px 0px transparent}.ibo-button.ibo-is-alternative.ibo-is-secondary,.ui-dialog .ibo-is-alternative.ibo-is-secondary.ui-button,.ui-dialog .ibo-is-secondary.ui-button.ui-dialog-titlebar-close,.ui-dialog .ui-button.ui-dialog-titlebar-close,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close,.ui-dialog .ibo-is-alternative.ui-button,.ui-dialog .ibo-is-alternative.ui-button.ui-datepicker-current,.ui-dialog .ui-button.ui-datepicker-current.ui-dialog-titlebar-close,.ui-dialog .ibo-is-alternative.ui-button.ui-datepicker-close,.ui-dialog .ui-button.ui-datepicker-close.ui-dialog-titlebar-close,.ibo-is-alternative.ibo-is-secondary.ui-datepicker-current,.ui-dialog .ibo-is-secondary.ui-datepicker-current.ui-button.ui-dialog-titlebar-close,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close.ui-datepicker-close,.ui-dialog .ibo-is-alternative.ui-datepicker-current.ui-button,.ibo-is-alternative.ui-datepicker-current,.ibo-is-alternative.ui-datepicker-current.ui-datepicker-close,.ui-dialog .ui-datepicker-current.ui-datepicker-close.ui-button.ui-dialog-titlebar-close,.ibo-is-alternative.ibo-is-secondary.ui-datepicker-close,.ui-dialog .ibo-is-secondary.ui-datepicker-close.ui-button.ui-dialog-titlebar-close,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close.ui-datepicker-current,.ui-dialog .ibo-is-alternative.ui-datepicker-close.ui-button,.ibo-is-alternative.ui-datepicker-close.ui-datepicker-current,.ui-dialog .ui-datepicker-close.ui-datepicker-current.ui-button.ui-dialog-titlebar-close,.ibo-is-alternative.ui-datepicker-close,.ui-dialog .ibo-button.ibo-is-secondary.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-is-secondary.ui-button.ui-dialog-titlebar-close.ui-datepicker-current,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current.ui-datepicker-close,.ui-dialog .ibo-is-secondary.ui-button.ui-dialog-titlebar-close.ui-datepicker-close,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close.ui-datepicker-current,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close.ui-datepicker-current,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close.ui-datepicker-close,.ui-dialog .ibo-button.ibo-is-alternative.ui-button,.ibo-button.ibo-is-alternative.ui-datepicker-current,.ui-dialog .ibo-button.ui-datepicker-current.ui-button.ui-dialog-titlebar-close,.ibo-button.ibo-is-alternative.ui-datepicker-close,.ui-dialog .ibo-button.ui-datepicker-close.ui-button.ui-dialog-titlebar-close{background-color:transparent;color:#212934;box-shadow:0px 2px 0px transparent}.ibo-button.ibo-is-alternative.ibo-is-secondary:hover,.ui-dialog .ibo-is-alternative.ibo-is-secondary.ui-button:hover,.ui-dialog .ibo-is-secondary.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current:hover,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close:hover,.ui-dialog .ibo-is-alternative.ui-button:hover,.ui-dialog .ibo-is-alternative.ui-button.ui-datepicker-current:hover,.ui-dialog .ui-button.ui-datepicker-current.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-is-alternative.ui-button.ui-datepicker-close:hover,.ui-dialog .ui-button.ui-datepicker-close.ui-dialog-titlebar-close:hover,.ibo-is-alternative.ibo-is-secondary.ui-datepicker-current:hover,.ui-dialog .ibo-is-secondary.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:hover,.ui-dialog .ibo-is-alternative.ui-datepicker-current.ui-button:hover,.ibo-is-alternative.ui-datepicker-current:hover,.ibo-is-alternative.ui-datepicker-current.ui-datepicker-close:hover,.ui-dialog .ui-datepicker-current.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:hover,.ibo-is-alternative.ibo-is-secondary.ui-datepicker-close:hover,.ui-dialog .ibo-is-secondary.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:hover,.ui-dialog .ibo-is-alternative.ui-datepicker-close.ui-button:hover,.ibo-is-alternative.ui-datepicker-close.ui-datepicker-current:hover,.ui-dialog .ui-datepicker-close.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:hover,.ibo-is-alternative.ui-datepicker-close:hover,.ui-dialog .ibo-button.ibo-is-secondary.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-is-secondary.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:hover,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current.ui-datepicker-close:hover,.ui-dialog .ibo-is-secondary.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:hover,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close.ui-datepicker-current:hover,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:hover,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:hover,.ui-dialog .ibo-button.ibo-is-alternative.ui-button:hover,.ibo-button.ibo-is-alternative.ui-datepicker-current:hover,.ui-dialog .ibo-button.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:hover,.ibo-button.ibo-is-alternative.ui-datepicker-close:hover,.ui-dialog .ibo-button.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:hover{background-color:#f8f9fa;color:#212934;box-shadow:0px 2px 0px #f8f9fa}.ibo-button.ibo-is-alternative.ibo-is-secondary:active,.ui-dialog .ibo-is-alternative.ibo-is-secondary.ui-button:active,.ui-dialog .ibo-is-secondary.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current:active,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close:active,.ui-dialog .ibo-is-alternative.ui-button:active,.ui-dialog .ibo-is-alternative.ui-button.ui-datepicker-current:active,.ui-dialog .ui-button.ui-datepicker-current.ui-dialog-titlebar-close:active,.ui-dialog .ibo-is-alternative.ui-button.ui-datepicker-close:active,.ui-dialog .ui-button.ui-datepicker-close.ui-dialog-titlebar-close:active,.ibo-is-alternative.ibo-is-secondary.ui-datepicker-current:active,.ui-dialog .ibo-is-secondary.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:active,.ui-dialog .ibo-is-alternative.ui-datepicker-current.ui-button:active,.ibo-is-alternative.ui-datepicker-current:active,.ibo-is-alternative.ui-datepicker-current.ui-datepicker-close:active,.ui-dialog .ui-datepicker-current.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:active,.ibo-is-alternative.ibo-is-secondary.ui-datepicker-close:active,.ui-dialog .ibo-is-secondary.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:active,.ui-dialog .ibo-is-alternative.ui-datepicker-close.ui-button:active,.ibo-is-alternative.ui-datepicker-close.ui-datepicker-current:active,.ui-dialog .ui-datepicker-close.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:active,.ibo-is-alternative.ui-datepicker-close:active,.ui-dialog .ibo-button.ibo-is-secondary.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-is-secondary.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:active,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current.ui-datepicker-close:active,.ui-dialog .ibo-is-secondary.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:active,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close.ui-datepicker-current:active,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:active,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:active,.ui-dialog .ibo-button.ibo-is-alternative.ui-button:active,.ibo-button.ibo-is-alternative.ui-datepicker-current:active,.ui-dialog .ibo-button.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:active,.ibo-button.ibo-is-alternative.ui-datepicker-close:active,.ui-dialog .ibo-button.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:active{background-color:#f8f9fa;color:#212934;box-shadow:inset 0px 2px 0px #e1e7ec , 0px 2px 0px #f8f9fa}.ibo-button.ibo-is-alternative.ibo-is-secondary:disabled,.ui-dialog .ibo-is-alternative.ibo-is-secondary.ui-button:disabled,.ui-dialog .ibo-is-secondary.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current:disabled,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close:disabled,.ui-dialog .ibo-is-alternative.ui-button:disabled,.ui-dialog .ibo-is-alternative.ui-button.ui-datepicker-current:disabled,.ui-dialog .ui-button.ui-datepicker-current.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-is-alternative.ui-button.ui-datepicker-close:disabled,.ui-dialog .ui-button.ui-datepicker-close.ui-dialog-titlebar-close:disabled,.ibo-is-alternative.ibo-is-secondary.ui-datepicker-current:disabled,.ui-dialog .ibo-is-secondary.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:disabled,.ui-dialog .ibo-is-alternative.ui-datepicker-current.ui-button:disabled,.ibo-is-alternative.ui-datepicker-current:disabled,.ibo-is-alternative.ui-datepicker-current.ui-datepicker-close:disabled,.ui-dialog .ui-datepicker-current.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:disabled,.ibo-is-alternative.ibo-is-secondary.ui-datepicker-close:disabled,.ui-dialog .ibo-is-secondary.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:disabled,.ui-dialog .ibo-is-alternative.ui-datepicker-close.ui-button:disabled,.ibo-is-alternative.ui-datepicker-close.ui-datepicker-current:disabled,.ui-dialog .ui-datepicker-close.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:disabled,.ibo-is-alternative.ui-datepicker-close:disabled,.ui-dialog .ibo-button.ibo-is-secondary.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-is-secondary.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:disabled,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current.ui-datepicker-close:disabled,.ui-dialog .ibo-is-secondary.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:disabled,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close.ui-datepicker-current:disabled,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:disabled,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:disabled,.ui-dialog .ibo-button.ibo-is-alternative.ui-button:disabled,.ibo-button.ibo-is-alternative.ui-datepicker-current:disabled,.ui-dialog .ibo-button.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:disabled,.ibo-button.ibo-is-alternative.ui-datepicker-close:disabled,.ui-dialog .ibo-button.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:disabled{background-color:transparent;color:#929fb1;box-shadow:inset 0px 2px 0px transparent}.ibo-button.ibo-is-alternative.ibo-is-danger,.ui-dialog .ibo-is-alternative.ibo-is-danger.ui-button,.ui-dialog .ibo-is-danger.ui-button.ui-dialog-titlebar-close,.ibo-is-alternative.ibo-is-danger.ui-datepicker-current,.ui-dialog .ibo-is-danger.ui-datepicker-current.ui-button.ui-dialog-titlebar-close,.ibo-is-alternative.ibo-is-danger.ui-datepicker-close,.ui-dialog .ibo-is-danger.ui-datepicker-close.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-button.ibo-is-danger.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-is-danger.ui-button.ui-dialog-titlebar-close.ui-datepicker-current,.ui-dialog .ibo-is-danger.ui-button.ui-dialog-titlebar-close.ui-datepicker-close{background-color:transparent;color:#c53030;box-shadow:0px 2px 0px transparent}.ibo-button.ibo-is-alternative.ibo-is-danger:hover,.ui-dialog .ibo-is-alternative.ibo-is-danger.ui-button:hover,.ui-dialog .ibo-is-danger.ui-button.ui-dialog-titlebar-close:hover,.ibo-is-alternative.ibo-is-danger.ui-datepicker-current:hover,.ui-dialog .ibo-is-danger.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:hover,.ibo-is-alternative.ibo-is-danger.ui-datepicker-close:hover,.ui-dialog .ibo-is-danger.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-button.ibo-is-danger.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-is-danger.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:hover,.ui-dialog .ibo-is-danger.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:hover{background-color:#fed7d7;color:#742a2a;box-shadow:0px 2px 0px #fed7d7}.ibo-button.ibo-is-alternative.ibo-is-danger:active,.ui-dialog .ibo-is-alternative.ibo-is-danger.ui-button:active,.ui-dialog .ibo-is-danger.ui-button.ui-dialog-titlebar-close:active,.ibo-is-alternative.ibo-is-danger.ui-datepicker-current:active,.ui-dialog .ibo-is-danger.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:active,.ibo-is-alternative.ibo-is-danger.ui-datepicker-close:active,.ui-dialog .ibo-is-danger.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-button.ibo-is-danger.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-is-danger.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:active,.ui-dialog .ibo-is-danger.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:active{background-color:#fed7d7;color:#742a2a;box-shadow:inset 0px 2px 0px #c53030 , 0px 2px 0px #fed7d7}.ibo-button.ibo-is-alternative.ibo-is-danger:disabled,.ui-dialog .ibo-is-alternative.ibo-is-danger.ui-button:disabled,.ui-dialog .ibo-is-danger.ui-button.ui-dialog-titlebar-close:disabled,.ibo-is-alternative.ibo-is-danger.ui-datepicker-current:disabled,.ui-dialog .ibo-is-danger.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:disabled,.ibo-is-alternative.ibo-is-danger.ui-datepicker-close:disabled,.ui-dialog .ibo-is-danger.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-button.ibo-is-danger.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-is-danger.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:disabled,.ui-dialog .ibo-is-danger.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:disabled{background-color:transparent;color:#929fb1;box-shadow:inset 0px 2px 0px transparent}.ibo-button.ibo-is-alternative.ibo-is-success,.ui-dialog .ibo-is-alternative.ibo-is-success.ui-button,.ui-dialog .ibo-is-success.ui-button.ui-dialog-titlebar-close,.ibo-is-alternative.ibo-is-success.ui-datepicker-current,.ui-dialog .ibo-is-success.ui-datepicker-current.ui-button.ui-dialog-titlebar-close,.ibo-is-alternative.ibo-is-success.ui-datepicker-close,.ui-dialog .ibo-is-success.ui-datepicker-close.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-button.ibo-is-success.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-is-success.ui-button.ui-dialog-titlebar-close.ui-datepicker-current,.ui-dialog .ibo-is-success.ui-button.ui-dialog-titlebar-close.ui-datepicker-close{background-color:transparent;color:#33691e;box-shadow:0px 2px 0px transparent}.ibo-button.ibo-is-alternative.ibo-is-success:hover,.ui-dialog .ibo-is-alternative.ibo-is-success.ui-button:hover,.ui-dialog .ibo-is-success.ui-button.ui-dialog-titlebar-close:hover,.ibo-is-alternative.ibo-is-success.ui-datepicker-current:hover,.ui-dialog .ibo-is-success.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:hover,.ibo-is-alternative.ibo-is-success.ui-datepicker-close:hover,.ui-dialog .ibo-is-success.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-button.ibo-is-success.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-is-success.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:hover,.ui-dialog .ibo-is-success.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:hover{background-color:#dcedc8;color:#33691e;box-shadow:0px 2px 0px #dcedc8}.ibo-button.ibo-is-alternative.ibo-is-success:active,.ui-dialog .ibo-is-alternative.ibo-is-success.ui-button:active,.ui-dialog .ibo-is-success.ui-button.ui-dialog-titlebar-close:active,.ibo-is-alternative.ibo-is-success.ui-datepicker-current:active,.ui-dialog .ibo-is-success.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:active,.ibo-is-alternative.ibo-is-success.ui-datepicker-close:active,.ui-dialog .ibo-is-success.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-button.ibo-is-success.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-is-success.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:active,.ui-dialog .ibo-is-success.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:active{background-color:#dcedc8;color:#33691e;box-shadow:inset 0px 2px 0px #689f38 , 0px 2px 0px #dcedc8}.ibo-button.ibo-is-alternative.ibo-is-success:disabled,.ui-dialog .ibo-is-alternative.ibo-is-success.ui-button:disabled,.ui-dialog .ibo-is-success.ui-button.ui-dialog-titlebar-close:disabled,.ibo-is-alternative.ibo-is-success.ui-datepicker-current:disabled,.ui-dialog .ibo-is-success.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:disabled,.ibo-is-alternative.ibo-is-success.ui-datepicker-close:disabled,.ui-dialog .ibo-is-success.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-button.ibo-is-success.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-is-success.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:disabled,.ui-dialog .ibo-is-success.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:disabled{background-color:transparent;color:#929fb1;box-shadow:inset 0px 2px 0px transparent}.ibo-button.ibo-is-alternative.ibo-is-red,.ui-dialog .ibo-is-alternative.ibo-is-red.ui-button,.ui-dialog .ibo-is-red.ui-button.ui-dialog-titlebar-close,.ibo-is-alternative.ibo-is-red.ui-datepicker-current,.ui-dialog .ibo-is-red.ui-datepicker-current.ui-button.ui-dialog-titlebar-close,.ibo-is-alternative.ibo-is-red.ui-datepicker-close,.ui-dialog .ibo-is-red.ui-datepicker-close.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-button.ibo-is-red.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-is-red.ui-button.ui-dialog-titlebar-close.ui-datepicker-current,.ui-dialog .ibo-is-red.ui-button.ui-dialog-titlebar-close.ui-datepicker-close{background-color:transparent;color:#c53030;box-shadow:0px 2px 0px transparent}.ibo-button.ibo-is-alternative.ibo-is-red:hover,.ui-dialog .ibo-is-alternative.ibo-is-red.ui-button:hover,.ui-dialog .ibo-is-red.ui-button.ui-dialog-titlebar-close:hover,.ibo-is-alternative.ibo-is-red.ui-datepicker-current:hover,.ui-dialog .ibo-is-red.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:hover,.ibo-is-alternative.ibo-is-red.ui-datepicker-close:hover,.ui-dialog .ibo-is-red.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-button.ibo-is-red.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-is-red.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:hover,.ui-dialog .ibo-is-red.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:hover{background-color:#fed7d7;color:#742a2a;box-shadow:0px 2px 0px #fed7d7}.ibo-button.ibo-is-alternative.ibo-is-red:active,.ui-dialog .ibo-is-alternative.ibo-is-red.ui-button:active,.ui-dialog .ibo-is-red.ui-button.ui-dialog-titlebar-close:active,.ibo-is-alternative.ibo-is-red.ui-datepicker-current:active,.ui-dialog .ibo-is-red.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:active,.ibo-is-alternative.ibo-is-red.ui-datepicker-close:active,.ui-dialog .ibo-is-red.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-button.ibo-is-red.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-is-red.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:active,.ui-dialog .ibo-is-red.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:active{background-color:#fed7d7;color:#742a2a;box-shadow:inset 0px 2px 0px #c53030 , 0px 2px 0px #fed7d7}.ibo-button.ibo-is-alternative.ibo-is-red:disabled,.ui-dialog .ibo-is-alternative.ibo-is-red.ui-button:disabled,.ui-dialog .ibo-is-red.ui-button.ui-dialog-titlebar-close:disabled,.ibo-is-alternative.ibo-is-red.ui-datepicker-current:disabled,.ui-dialog .ibo-is-red.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:disabled,.ibo-is-alternative.ibo-is-red.ui-datepicker-close:disabled,.ui-dialog .ibo-is-red.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-button.ibo-is-red.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-is-red.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:disabled,.ui-dialog .ibo-is-red.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:disabled{background-color:transparent;color:#929fb1;box-shadow:inset 0px 2px 0px transparent}.ibo-button.ibo-is-alternative.ibo-is-green,.ui-dialog .ibo-is-alternative.ibo-is-green.ui-button,.ui-dialog .ibo-is-green.ui-button.ui-dialog-titlebar-close,.ibo-is-alternative.ibo-is-green.ui-datepicker-current,.ui-dialog .ibo-is-green.ui-datepicker-current.ui-button.ui-dialog-titlebar-close,.ibo-is-alternative.ibo-is-green.ui-datepicker-close,.ui-dialog .ibo-is-green.ui-datepicker-close.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-button.ibo-is-green.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-is-green.ui-button.ui-dialog-titlebar-close.ui-datepicker-current,.ui-dialog .ibo-is-green.ui-button.ui-dialog-titlebar-close.ui-datepicker-close{background-color:transparent;color:#33691e;box-shadow:0px 2px 0px transparent}.ibo-button.ibo-is-alternative.ibo-is-green:hover,.ui-dialog .ibo-is-alternative.ibo-is-green.ui-button:hover,.ui-dialog .ibo-is-green.ui-button.ui-dialog-titlebar-close:hover,.ibo-is-alternative.ibo-is-green.ui-datepicker-current:hover,.ui-dialog .ibo-is-green.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:hover,.ibo-is-alternative.ibo-is-green.ui-datepicker-close:hover,.ui-dialog .ibo-is-green.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-button.ibo-is-green.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-is-green.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:hover,.ui-dialog .ibo-is-green.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:hover{background-color:#dcedc8;color:#33691e;box-shadow:0px 2px 0px #dcedc8}.ibo-button.ibo-is-alternative.ibo-is-green:active,.ui-dialog .ibo-is-alternative.ibo-is-green.ui-button:active,.ui-dialog .ibo-is-green.ui-button.ui-dialog-titlebar-close:active,.ibo-is-alternative.ibo-is-green.ui-datepicker-current:active,.ui-dialog .ibo-is-green.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:active,.ibo-is-alternative.ibo-is-green.ui-datepicker-close:active,.ui-dialog .ibo-is-green.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-button.ibo-is-green.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-is-green.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:active,.ui-dialog .ibo-is-green.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:active{background-color:#dcedc8;color:#33691e;box-shadow:inset 0px 2px 0px #689f38 , 0px 2px 0px #dcedc8}.ibo-button.ibo-is-alternative.ibo-is-green:disabled,.ui-dialog .ibo-is-alternative.ibo-is-green.ui-button:disabled,.ui-dialog .ibo-is-green.ui-button.ui-dialog-titlebar-close:disabled,.ibo-is-alternative.ibo-is-green.ui-datepicker-current:disabled,.ui-dialog .ibo-is-green.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:disabled,.ibo-is-alternative.ibo-is-green.ui-datepicker-close:disabled,.ui-dialog .ibo-is-green.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-button.ibo-is-green.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-is-green.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:disabled,.ui-dialog .ibo-is-green.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:disabled{background-color:transparent;color:#929fb1;box-shadow:inset 0px 2px 0px transparent}.ibo-button.ibo-is-alternative.ibo-is-cyan,.ui-dialog .ibo-is-alternative.ibo-is-cyan.ui-button,.ui-dialog .ibo-is-cyan.ui-button.ui-dialog-titlebar-close,.ibo-is-alternative.ibo-is-cyan.ui-datepicker-current,.ui-dialog .ibo-is-cyan.ui-datepicker-current.ui-button.ui-dialog-titlebar-close,.ibo-is-alternative.ibo-is-cyan.ui-datepicker-close,.ui-dialog .ibo-is-cyan.ui-datepicker-close.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-button.ibo-is-cyan.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-is-cyan.ui-button.ui-dialog-titlebar-close.ui-datepicker-current,.ui-dialog .ibo-is-cyan.ui-button.ui-dialog-titlebar-close.ui-datepicker-close{background-color:transparent;color:#006164;box-shadow:0px 2px 0px transparent}.ibo-button.ibo-is-alternative.ibo-is-cyan:hover,.ui-dialog .ibo-is-alternative.ibo-is-cyan.ui-button:hover,.ui-dialog .ibo-is-cyan.ui-button.ui-dialog-titlebar-close:hover,.ibo-is-alternative.ibo-is-cyan.ui-datepicker-current:hover,.ui-dialog .ibo-is-cyan.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:hover,.ibo-is-alternative.ibo-is-cyan.ui-datepicker-close:hover,.ui-dialog .ibo-is-cyan.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-button.ibo-is-cyan.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-is-cyan.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:hover,.ui-dialog .ibo-is-cyan.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:hover{background-color:#c9eef2;color:#006164;box-shadow:0px 2px 0px #c9eef2}.ibo-button.ibo-is-alternative.ibo-is-cyan:active,.ui-dialog .ibo-is-alternative.ibo-is-cyan.ui-button:active,.ui-dialog .ibo-is-cyan.ui-button.ui-dialog-titlebar-close:active,.ibo-is-alternative.ibo-is-cyan.ui-datepicker-current:active,.ui-dialog .ibo-is-cyan.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:active,.ibo-is-alternative.ibo-is-cyan.ui-datepicker-close:active,.ui-dialog .ibo-is-cyan.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-button.ibo-is-cyan.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-is-cyan.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:active,.ui-dialog .ibo-is-cyan.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:active{background-color:#c9eef2;color:#006164;box-shadow:inset 0px 2px 0px #00838f , 0px 2px 0px #c9eef2}.ibo-button.ibo-is-alternative.ibo-is-cyan:disabled,.ui-dialog .ibo-is-alternative.ibo-is-cyan.ui-button:disabled,.ui-dialog .ibo-is-cyan.ui-button.ui-dialog-titlebar-close:disabled,.ibo-is-alternative.ibo-is-cyan.ui-datepicker-current:disabled,.ui-dialog .ibo-is-cyan.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:disabled,.ibo-is-alternative.ibo-is-cyan.ui-datepicker-close:disabled,.ui-dialog .ibo-is-cyan.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-button.ibo-is-cyan.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-is-cyan.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:disabled,.ui-dialog .ibo-is-cyan.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:disabled{background-color:transparent;color:#929fb1;box-shadow:inset 0px 2px 0px transparent}.ibo-button,.ui-dialog .ui-button,.ui-datepicker-current,.ui-datepicker-close{position:relative;display:inline-block;padding:6px 9px;border:0;border-radius:4px;cursor:pointer;text-transform:uppercase;white-space:nowrap}.ibo-button.ibo-action-button,.ui-dialog .ibo-action-button.ui-button,.ibo-action-button.ui-datepicker-current,.ibo-action-button.ui-datepicker-close{float:right}.ibo-button .ibo-button--loading-icon,.ui-dialog .ui-button .ibo-button--loading-icon,.ui-datepicker-current .ibo-button--loading-icon,.ui-datepicker-close .ibo-button--loading-icon{display:none}.ibo-button.ibo-is-loading .ibo-button--icon,.ui-dialog .ibo-is-loading.ui-button .ibo-button--icon,.ibo-is-loading.ui-datepicker-current .ibo-button--icon,.ibo-is-loading.ui-datepicker-close .ibo-button--icon{display:none}.ibo-button.ibo-is-loading .ibo-button--loading-icon,.ui-dialog .ibo-is-loading.ui-button .ibo-button--loading-icon,.ibo-is-loading.ui-datepicker-current .ibo-button--loading-icon,.ibo-is-loading.ui-datepicker-close .ibo-button--loading-icon{display:inline-block}.ibo-button.ibo-is-loading .ibo-button--loading-icon+.ibo-button--label,.ui-dialog .ibo-is-loading.ui-button .ibo-button--loading-icon+.ibo-button--label,.ibo-is-loading.ui-datepicker-current .ibo-button--loading-icon+.ibo-button--label,.ibo-is-loading.ui-datepicker-close .ibo-button--loading-icon+.ibo-button--label{margin-left:4px}.ibo-button--icon+.ibo-button--label{margin-left:4px}.ibo-button--vertical-align{margin-top:4px;margin-bottom:4px}.ibo-button-group{display:inline-flex;flex-wrap:nowrap}.ibo-button-group .ibo-button,.ibo-button-group .ui-dialog .ui-button,.ui-dialog .ibo-button-group .ui-button,.ibo-button-group .ui-datepicker-current,.ibo-button-group .ui-datepicker-close{position:relative}.ibo-button-group .ibo-button:first-child,.ibo-button-group .ui-dialog .ui-button:first-child,.ui-dialog .ibo-button-group .ui-button:first-child,.ibo-button-group .ui-datepicker-current:first-child,.ibo-button-group .ui-datepicker-close:first-child{border-radius:4px 0 0 4px}.ibo-button-group .ibo-button:last-child,.ibo-button-group .ui-dialog .ui-button:last-child,.ui-dialog .ibo-button-group .ui-button:last-child,.ibo-button-group .ui-datepicker-current:last-child,.ibo-button-group .ui-datepicker-close:last-child{border-radius:0 4px 4px 0}.ibo-button-group .ibo-button:not(:first-child):not(:last-child),.ibo-button-group .ui-dialog .ui-button:not(:first-child):not(:last-child),.ui-dialog .ibo-button-group .ui-button:not(:first-child):not(:last-child),.ibo-button-group .ui-datepicker-current:not(:first-child):not(:last-child),.ibo-button-group .ui-datepicker-close:not(:first-child):not(:last-child){border-radius:0}.ibo-button-group .ibo-button+.ibo-button,.ibo-button-group .ui-dialog .ui-button+.ibo-button,.ibo-button-group .ui-dialog .ui-dialog .ui-button+.ui-button,.ui-dialog .ibo-button-group .ui-dialog .ui-button+.ui-button,.ibo-button-group .ui-dialog .ui-button+.ui-datepicker-current,.ibo-button-group .ui-dialog .ui-button+.ui-datepicker-close,.ui-dialog .ibo-button-group .ui-button+.ibo-button,.ibo-button-group .ui-datepicker-current+.ibo-button,.ibo-button-group .ui-dialog .ui-datepicker-current+.ui-button,.ui-dialog .ibo-button-group .ui-datepicker-current+.ui-button,.ibo-button-group .ui-datepicker-current+.ui-datepicker-current,.ibo-button-group .ui-datepicker-current+.ui-datepicker-close,.ibo-button-group .ui-datepicker-close+.ibo-button,.ibo-button-group .ui-dialog .ui-datepicker-close+.ui-button,.ui-dialog .ibo-button-group .ui-datepicker-close+.ui-button,.ibo-button-group .ui-datepicker-close+.ui-datepicker-current,.ibo-button-group .ui-datepicker-close+.ui-datepicker-close,.ibo-button-group .ui-dialog .ibo-button+.ui-button,.ui-dialog .ibo-button-group .ibo-button+.ui-button,.ibo-button-group .ibo-button+.ui-datepicker-current,.ibo-button-group .ibo-button+.ui-datepicker-close{margin-left:0}.ibo-button-group .ibo-button+.ibo-button::before,.ibo-button-group .ui-dialog .ui-button+.ibo-button::before,.ui-dialog .ibo-button-group .ui-button+.ibo-button::before,.ibo-button-group .ui-datepicker-current+.ibo-button::before,.ibo-button-group .ui-datepicker-close+.ibo-button::before,.ibo-button-group .ui-dialog .ibo-button+.ui-button::before,.ui-dialog .ibo-button-group .ibo-button+.ui-button::before,.ibo-button-group .ibo-button+.ui-datepicker-current::before,.ibo-button-group .ibo-button+.ui-datepicker-close::before{content:"";position:absolute;top:6px;bottom:6px;left:0;width:1px;border-left:1px solid transparent}.ibo-button-group>*+*.ibo-is-regular.ibo-is-neutral::before,.ui-dialog .ibo-button-group>*+*.ibo-is-neutral.ui-button::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close::before,.ibo-button-group>*+*.ibo-is-neutral.ui-datepicker-current::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-current.ui-button.ui-dialog-titlebar-close::before,.ibo-button-group>*+*.ibo-is-neutral.ui-datepicker-close::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-close.ui-button.ui-dialog-titlebar-close::before,.ui-dialog .ibo-button-group>*+*.ibo-is-regular.ui-button.ui-dialog-titlebar-close::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close.ui-datepicker-current::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close.ui-datepicker-close::before{border-left-color:#d5dde5}.ibo-button-group>*+*.ibo-is-regular.ibo-is-neutral:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-neutral.ui-button:hover::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close:hover::before,.ibo-button-group>*+*.ibo-is-neutral.ui-datepicker-current:hover::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:hover::before,.ibo-button-group>*+*.ibo-is-neutral.ui-datepicker-close:hover::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-regular.ui-button.ui-dialog-titlebar-close:hover::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:hover::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:hover::before{border-left-color:#d5dde5}.ibo-button-group>*+*.ibo-is-regular.ibo-is-neutral:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-neutral.ui-button:active::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close:active::before,.ibo-button-group>*+*.ibo-is-neutral.ui-datepicker-current:active::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:active::before,.ibo-button-group>*+*.ibo-is-neutral.ui-datepicker-close:active::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-regular.ui-button.ui-dialog-titlebar-close:active::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:active::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:active::before{border-left-color:#e1e7ec}.ibo-button-group>*+*.ibo-is-regular.ibo-is-neutral:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-neutral.ui-button:disabled::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close:disabled::before,.ibo-button-group>*+*.ibo-is-neutral.ui-datepicker-current:disabled::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:disabled::before,.ibo-button-group>*+*.ibo-is-neutral.ui-datepicker-close:disabled::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-regular.ui-button.ui-dialog-titlebar-close:disabled::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:disabled::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:disabled::before{border-left-color:#aebecd}.ibo-button-group>*+*.ibo-is-regular.ibo-is-primary::before,.ui-dialog .ibo-button-group>*+*.ibo-is-primary.ui-button::before,.ibo-button-group>*+*.ibo-is-primary.ui-datepicker-current::before,.ibo-button-group>*+*.ibo-is-primary.ui-datepicker-close::before{border-left-color:#006164}.ibo-button-group>*+*.ibo-is-regular.ibo-is-primary:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-primary.ui-button:hover::before,.ibo-button-group>*+*.ibo-is-primary.ui-datepicker-current:hover::before,.ibo-button-group>*+*.ibo-is-primary.ui-datepicker-close:hover::before{border-left-color:#006164}.ibo-button-group>*+*.ibo-is-regular.ibo-is-primary:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-primary.ui-button:active::before,.ibo-button-group>*+*.ibo-is-primary.ui-datepicker-current:active::before,.ibo-button-group>*+*.ibo-is-primary.ui-datepicker-close:active::before{border-left-color:#006164}.ibo-button-group>*+*.ibo-is-regular.ibo-is-primary:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-primary.ui-button:disabled::before,.ibo-button-group>*+*.ibo-is-primary.ui-datepicker-current:disabled::before,.ibo-button-group>*+*.ibo-is-primary.ui-datepicker-close:disabled::before{border-left-color:#aebecd}.ibo-button-group>*+*.ibo-is-regular.ibo-is-secondary::before,.ui-dialog .ibo-button-group>*+*.ibo-is-secondary.ui-button::before,.ui-dialog .ibo-button-group>*+*.ui-button::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-datepicker-current::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-datepicker-close::before,.ibo-button-group>*+*.ibo-is-secondary.ui-datepicker-current::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-current.ui-button::before,.ibo-button-group>*+*.ui-datepicker-current::before,.ibo-button-group>*+*.ui-datepicker-current.ui-datepicker-close::before,.ibo-button-group>*+*.ibo-is-secondary.ui-datepicker-close::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-close.ui-button::before,.ibo-button-group>*+*.ui-datepicker-close.ui-datepicker-current::before,.ibo-button-group>*+*.ui-datepicker-close::before,.ui-dialog .ibo-button-group>*+*.ibo-is-regular.ui-button::before,.ibo-button-group>*+*.ibo-is-regular.ui-datepicker-current::before,.ibo-button-group>*+*.ibo-is-regular.ui-datepicker-close::before{border-left-color:#d5dde5}.ibo-button-group>*+*.ibo-is-regular.ibo-is-secondary:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-secondary.ui-button:hover::before,.ui-dialog .ibo-button-group>*+*.ui-button:hover::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-datepicker-current:hover::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-datepicker-close:hover::before,.ibo-button-group>*+*.ibo-is-secondary.ui-datepicker-current:hover::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-current.ui-button:hover::before,.ibo-button-group>*+*.ui-datepicker-current:hover::before,.ibo-button-group>*+*.ui-datepicker-current.ui-datepicker-close:hover::before,.ibo-button-group>*+*.ibo-is-secondary.ui-datepicker-close:hover::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-close.ui-button:hover::before,.ibo-button-group>*+*.ui-datepicker-close.ui-datepicker-current:hover::before,.ibo-button-group>*+*.ui-datepicker-close:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-regular.ui-button:hover::before,.ibo-button-group>*+*.ibo-is-regular.ui-datepicker-current:hover::before,.ibo-button-group>*+*.ibo-is-regular.ui-datepicker-close:hover::before{border-left-color:#d5dde5}.ibo-button-group>*+*.ibo-is-regular.ibo-is-secondary:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-secondary.ui-button:active::before,.ui-dialog .ibo-button-group>*+*.ui-button:active::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-datepicker-current:active::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-datepicker-close:active::before,.ibo-button-group>*+*.ibo-is-secondary.ui-datepicker-current:active::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-current.ui-button:active::before,.ibo-button-group>*+*.ui-datepicker-current:active::before,.ibo-button-group>*+*.ui-datepicker-current.ui-datepicker-close:active::before,.ibo-button-group>*+*.ibo-is-secondary.ui-datepicker-close:active::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-close.ui-button:active::before,.ibo-button-group>*+*.ui-datepicker-close.ui-datepicker-current:active::before,.ibo-button-group>*+*.ui-datepicker-close:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-regular.ui-button:active::before,.ibo-button-group>*+*.ibo-is-regular.ui-datepicker-current:active::before,.ibo-button-group>*+*.ibo-is-regular.ui-datepicker-close:active::before{border-left-color:#e1e7ec}.ibo-button-group>*+*.ibo-is-regular.ibo-is-secondary:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-secondary.ui-button:disabled::before,.ui-dialog .ibo-button-group>*+*.ui-button:disabled::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-datepicker-current:disabled::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-datepicker-close:disabled::before,.ibo-button-group>*+*.ibo-is-secondary.ui-datepicker-current:disabled::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-current.ui-button:disabled::before,.ibo-button-group>*+*.ui-datepicker-current:disabled::before,.ibo-button-group>*+*.ui-datepicker-current.ui-datepicker-close:disabled::before,.ibo-button-group>*+*.ibo-is-secondary.ui-datepicker-close:disabled::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-close.ui-button:disabled::before,.ibo-button-group>*+*.ui-datepicker-close.ui-datepicker-current:disabled::before,.ibo-button-group>*+*.ui-datepicker-close:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-regular.ui-button:disabled::before,.ibo-button-group>*+*.ibo-is-regular.ui-datepicker-current:disabled::before,.ibo-button-group>*+*.ibo-is-regular.ui-datepicker-close:disabled::before{border-left-color:#aebecd}.ibo-button-group>*+*.ibo-is-regular.ibo-is-danger::before,.ui-dialog .ibo-button-group>*+*.ibo-is-danger.ui-button::before,.ibo-button-group>*+*.ibo-is-danger.ui-datepicker-current::before,.ibo-button-group>*+*.ibo-is-danger.ui-datepicker-close::before{border-left-color:#9b2c2c}.ibo-button-group>*+*.ibo-is-regular.ibo-is-danger:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-danger.ui-button:hover::before,.ibo-button-group>*+*.ibo-is-danger.ui-datepicker-current:hover::before,.ibo-button-group>*+*.ibo-is-danger.ui-datepicker-close:hover::before{border-left-color:#9b2c2c}.ibo-button-group>*+*.ibo-is-regular.ibo-is-danger:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-danger.ui-button:active::before,.ibo-button-group>*+*.ibo-is-danger.ui-datepicker-current:active::before,.ibo-button-group>*+*.ibo-is-danger.ui-datepicker-close:active::before{border-left-color:#9b2c2c}.ibo-button-group>*+*.ibo-is-regular.ibo-is-danger:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-danger.ui-button:disabled::before,.ibo-button-group>*+*.ibo-is-danger.ui-datepicker-current:disabled::before,.ibo-button-group>*+*.ibo-is-danger.ui-datepicker-close:disabled::before{border-left-color:#aebecd}.ibo-button-group>*+*.ibo-is-regular.ibo-is-success::before,.ui-dialog .ibo-button-group>*+*.ibo-is-success.ui-button::before,.ibo-button-group>*+*.ibo-is-success.ui-datepicker-current::before,.ibo-button-group>*+*.ibo-is-success.ui-datepicker-close::before{border-left-color:#33691e}.ibo-button-group>*+*.ibo-is-regular.ibo-is-success:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-success.ui-button:hover::before,.ibo-button-group>*+*.ibo-is-success.ui-datepicker-current:hover::before,.ibo-button-group>*+*.ibo-is-success.ui-datepicker-close:hover::before{border-left-color:#33691e}.ibo-button-group>*+*.ibo-is-regular.ibo-is-success:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-success.ui-button:active::before,.ibo-button-group>*+*.ibo-is-success.ui-datepicker-current:active::before,.ibo-button-group>*+*.ibo-is-success.ui-datepicker-close:active::before{border-left-color:#33691e}.ibo-button-group>*+*.ibo-is-regular.ibo-is-success:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-success.ui-button:disabled::before,.ibo-button-group>*+*.ibo-is-success.ui-datepicker-current:disabled::before,.ibo-button-group>*+*.ibo-is-success.ui-datepicker-close:disabled::before{border-left-color:#aebecd}.ibo-button-group>*+*.ibo-is-regular.ibo-is-red::before,.ui-dialog .ibo-button-group>*+*.ibo-is-red.ui-button::before,.ibo-button-group>*+*.ibo-is-red.ui-datepicker-current::before,.ibo-button-group>*+*.ibo-is-red.ui-datepicker-close::before{border-left-color:#9b2c2c}.ibo-button-group>*+*.ibo-is-regular.ibo-is-red:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-red.ui-button:hover::before,.ibo-button-group>*+*.ibo-is-red.ui-datepicker-current:hover::before,.ibo-button-group>*+*.ibo-is-red.ui-datepicker-close:hover::before{border-left-color:#9b2c2c}.ibo-button-group>*+*.ibo-is-regular.ibo-is-red:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-red.ui-button:active::before,.ibo-button-group>*+*.ibo-is-red.ui-datepicker-current:active::before,.ibo-button-group>*+*.ibo-is-red.ui-datepicker-close:active::before{border-left-color:#9b2c2c}.ibo-button-group>*+*.ibo-is-regular.ibo-is-red:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-red.ui-button:disabled::before,.ibo-button-group>*+*.ibo-is-red.ui-datepicker-current:disabled::before,.ibo-button-group>*+*.ibo-is-red.ui-datepicker-close:disabled::before{border-left-color:#aebecd}.ibo-button-group>*+*.ibo-is-regular.ibo-is-green::before,.ui-dialog .ibo-button-group>*+*.ibo-is-green.ui-button::before,.ibo-button-group>*+*.ibo-is-green.ui-datepicker-current::before,.ibo-button-group>*+*.ibo-is-green.ui-datepicker-close::before{border-left-color:#33691e}.ibo-button-group>*+*.ibo-is-regular.ibo-is-green:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-green.ui-button:hover::before,.ibo-button-group>*+*.ibo-is-green.ui-datepicker-current:hover::before,.ibo-button-group>*+*.ibo-is-green.ui-datepicker-close:hover::before{border-left-color:#33691e}.ibo-button-group>*+*.ibo-is-regular.ibo-is-green:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-green.ui-button:active::before,.ibo-button-group>*+*.ibo-is-green.ui-datepicker-current:active::before,.ibo-button-group>*+*.ibo-is-green.ui-datepicker-close:active::before{border-left-color:#33691e}.ibo-button-group>*+*.ibo-is-regular.ibo-is-green:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-green.ui-button:disabled::before,.ibo-button-group>*+*.ibo-is-green.ui-datepicker-current:disabled::before,.ibo-button-group>*+*.ibo-is-green.ui-datepicker-close:disabled::before{border-left-color:#aebecd}.ibo-button-group>*+*.ibo-is-regular.ibo-is-cyan::before,.ui-dialog .ibo-button-group>*+*.ibo-is-cyan.ui-button::before,.ibo-button-group>*+*.ibo-is-cyan.ui-datepicker-current::before,.ibo-button-group>*+*.ibo-is-cyan.ui-datepicker-close::before{border-left-color:#006164}.ibo-button-group>*+*.ibo-is-regular.ibo-is-cyan:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-cyan.ui-button:hover::before,.ibo-button-group>*+*.ibo-is-cyan.ui-datepicker-current:hover::before,.ibo-button-group>*+*.ibo-is-cyan.ui-datepicker-close:hover::before{border-left-color:#006164}.ibo-button-group>*+*.ibo-is-regular.ibo-is-cyan:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-cyan.ui-button:active::before,.ibo-button-group>*+*.ibo-is-cyan.ui-datepicker-current:active::before,.ibo-button-group>*+*.ibo-is-cyan.ui-datepicker-close:active::before{border-left-color:#006164}.ibo-button-group>*+*.ibo-is-regular.ibo-is-cyan:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-cyan.ui-button:disabled::before,.ibo-button-group>*+*.ibo-is-cyan.ui-datepicker-current:disabled::before,.ibo-button-group>*+*.ibo-is-cyan.ui-datepicker-close:disabled::before{border-left-color:#aebecd}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-neutral::before,.ui-dialog .ibo-button-group>*+*.ibo-is-neutral.ui-button.ui-dialog-titlebar-close::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close::before,.ui-dialog .ibo-button-group>*+*.ibo-is-alternative.ui-button.ui-dialog-titlebar-close::before{border-left-color:#404b5a}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-neutral:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-neutral.ui-button.ui-dialog-titlebar-close:hover::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-alternative.ui-button.ui-dialog-titlebar-close:hover::before{border-left-color:#404b5a}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-neutral:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-neutral.ui-button.ui-dialog-titlebar-close:active::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-alternative.ui-button.ui-dialog-titlebar-close:active::before{border-left-color:#404b5a}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-neutral:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-neutral.ui-button.ui-dialog-titlebar-close:disabled::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-alternative.ui-button.ui-dialog-titlebar-close:disabled::before{border-left-color:#aebecd}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-primary::before,.ui-dialog .ibo-button-group>*+*.ibo-is-primary.ui-button.ui-dialog-titlebar-close::before{border-left-color:#00838f}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-primary:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-primary.ui-button.ui-dialog-titlebar-close:hover::before{border-left-color:#404b5a}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-primary:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-primary.ui-button.ui-dialog-titlebar-close:active::before{border-left-color:#404b5a}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-primary:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-primary.ui-button.ui-dialog-titlebar-close:disabled::before{border-left-color:#aebecd}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-secondary::before,.ui-dialog .ibo-button-group>*+*.ibo-is-secondary.ui-button.ui-dialog-titlebar-close::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close.ui-datepicker-current::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close.ui-datepicker-close::before,.ui-dialog .ibo-button-group>*+*.ibo-is-alternative.ui-button::before,.ibo-button-group>*+*.ibo-is-alternative.ui-datepicker-current::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-current.ui-button.ui-dialog-titlebar-close::before,.ibo-button-group>*+*.ibo-is-alternative.ui-datepicker-close::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-close.ui-button.ui-dialog-titlebar-close::before{border-left-color:#404b5a}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-secondary:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-secondary.ui-button.ui-dialog-titlebar-close:hover::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close:hover::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:hover::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-alternative.ui-button:hover::before,.ibo-button-group>*+*.ibo-is-alternative.ui-datepicker-current:hover::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:hover::before,.ibo-button-group>*+*.ibo-is-alternative.ui-datepicker-close:hover::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:hover::before{border-left-color:#404b5a}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-secondary:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-secondary.ui-button.ui-dialog-titlebar-close:active::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close:active::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:active::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-alternative.ui-button:active::before,.ibo-button-group>*+*.ibo-is-alternative.ui-datepicker-current:active::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:active::before,.ibo-button-group>*+*.ibo-is-alternative.ui-datepicker-close:active::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:active::before{border-left-color:#404b5a}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-secondary:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-secondary.ui-button.ui-dialog-titlebar-close:disabled::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close:disabled::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:disabled::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-alternative.ui-button:disabled::before,.ibo-button-group>*+*.ibo-is-alternative.ui-datepicker-current:disabled::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:disabled::before,.ibo-button-group>*+*.ibo-is-alternative.ui-datepicker-close:disabled::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:disabled::before{border-left-color:#aebecd}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-danger::before,.ui-dialog .ibo-button-group>*+*.ibo-is-danger.ui-button.ui-dialog-titlebar-close::before{border-left-color:#e53e3e}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-danger:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-danger.ui-button.ui-dialog-titlebar-close:hover::before{border-left-color:#9b2c2c}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-danger:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-danger.ui-button.ui-dialog-titlebar-close:active::before{border-left-color:#9b2c2c}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-danger:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-danger.ui-button.ui-dialog-titlebar-close:disabled::before{border-left-color:#aebecd}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-success::before,.ui-dialog .ibo-button-group>*+*.ibo-is-success.ui-button.ui-dialog-titlebar-close::before{border-left-color:#558b2f}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-success:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-success.ui-button.ui-dialog-titlebar-close:hover::before{border-left-color:#558b2f}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-success:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-success.ui-button.ui-dialog-titlebar-close:active::before{border-left-color:#558b2f}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-success:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-success.ui-button.ui-dialog-titlebar-close:disabled::before{border-left-color:#aebecd}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-red::before,.ui-dialog .ibo-button-group>*+*.ibo-is-red.ui-button.ui-dialog-titlebar-close::before{border-left-color:#e53e3e}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-red:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-red.ui-button.ui-dialog-titlebar-close:hover::before{border-left-color:#9b2c2c}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-red:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-red.ui-button.ui-dialog-titlebar-close:active::before{border-left-color:#9b2c2c}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-red:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-red.ui-button.ui-dialog-titlebar-close:disabled::before{border-left-color:#aebecd}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-green::before,.ui-dialog .ibo-button-group>*+*.ibo-is-green.ui-button.ui-dialog-titlebar-close::before{border-left-color:#558b2f}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-green:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-green.ui-button.ui-dialog-titlebar-close:hover::before{border-left-color:#558b2f}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-green:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-green.ui-button.ui-dialog-titlebar-close:active::before{border-left-color:#558b2f}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-green:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-green.ui-button.ui-dialog-titlebar-close:disabled::before{border-left-color:#aebecd}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-cyan::before,.ui-dialog .ibo-button-group>*+*.ibo-is-cyan.ui-button.ui-dialog-titlebar-close::before{border-left-color:#00838f}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-cyan:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-cyan.ui-button.ui-dialog-titlebar-close:hover::before{border-left-color:#00838f}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-cyan:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-cyan.ui-button.ui-dialog-titlebar-close:active::before{border-left-color:#00838f}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-cyan:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-cyan.ui-button.ui-dialog-titlebar-close:disabled::before{border-left-color:#aebecd}.ibo-breadcrumbs{position:relative;margin-right:32px}.ibo-breadcrumbs.ibo-is-overflowing{justify-content:right}.ibo-breadcrumbs *{display:flex;align-items:center}.ibo-breadcrumbs--item{color:#404b5a}.ibo-breadcrumbs--item:not(:last-child):hover .ibo-breadcrumbs--item-icon>*{opacity:1;filter:none}.ibo-breadcrumbs--item-icon{margin-right:8px;transition:all 0.1s linear}.ibo-breadcrumbs--item-icon>span{color:#929fb1;opacity:0.6}.ibo-breadcrumbs--item-icon>img{height:auto;max-width:16px;opacity:0.3;filter:grayscale(100%)}.ibo-breadcrumbs--item-label{display:inline;max-width:100px}.ibo-breadcrumbs--item:not(:last-child)::after,.ibo-breadcrumbs--previous-items-list-toggler:not(:last-child)::after{content:"";margin:0 12px;color:#aebecd}.ibo-breadcrumbs--previous-items-list-toggler{margin-right:24px;color:#6e7a8a !important}.ibo-breadcrumbs--previous-items-list-toggler:not(:last-child)::after{position:absolute;right:-24px}.ibo-breadcrumbs--previous-items-list{display:flex;flex-direction:column;align-items:stretch;position:fixed;top:37px;padding:8px 0;background-color:white}.ibo-breadcrumbs--previous-item{color:#404b5a;padding:12px 12px}.ibo-breadcrumbs--previous-item .ibo-breadcrumbs--item-label{max-width:200px}@keyframes ibo-quick-create--drawer--opening{from{top:-310px;box-shadow:none}to{top:100%;box-shadow:0 3px 6px rgba(0, 0, 0, 0.1), 0 10px 20px rgba(0, 0, 0, 0.15)}}.ibo-quick-create{position:relative}.ibo-quick-create.ibo-is-opened .ibo-quick-create--input,.ibo-quick-create.ibo-input-select-icon--menu .ibo-quick-create--input{width:245px}.ibo-quick-create.ibo-is-opened .ibo-quick-create--drawer,.ibo-quick-create.ibo-input-select-icon--menu .ibo-quick-create--drawer{animation-name:ibo-quick-create--drawer--opening;animation-delay:0.1s;animation-duration:0.2s;animation-direction:normal;animation-fill-mode:forwards}.ibo-quick-create--head{background-color:white}.ibo-quick-create--icon{color:#dd6c20;align-self:center;padding:0 16px}.ibo-quick-create--icon:hover{color:#c05621}.ibo-quick-create--icon:active{color:#9c4221}.ibo-quick-create--input{width:0;border:none;transition:all 0.2s ease-in-out}.ibo-quick-create--input.selectize-control.single{position:sticky;display:flex}.ibo-quick-create--input.selectize-control.single .selectize-input,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active{display:flex;background-color:transparent;background-image:none;border:none;box-shadow:none}.ibo-quick-create--input.selectize-control.single .selectize-input>input,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active>input{color:#404b5a;outline:none;border:none}.ibo-quick-create--input.selectize-control.single .selectize-input>input::placeholder,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active>input::placeholder{color:#929fb1}.ibo-quick-create--input.selectize-control.single .selectize-input>input:-ms-input-placeholder,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active>input:-ms-input-placeholder,.ibo-quick-create--input.selectize-control.single .selectize-input>input::-ms-input-placeholder,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active>input::-ms-input-placeholder{color:#929fb1}.ibo-quick-create--input.selectize-control.single .selectize-input>.item,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active>.item{color:#404b5a;line-height:200%}.ibo-quick-create--input.selectize-control.single .selectize-dropdown{background-color:white;border:none;border-radius:0}.ibo-quick-create--drawer{z-index:-1;position:absolute;left:0;right:0;top:-310px;padding:16px 16px;background-color:white;box-shadow:none}.ibo-quick-create--compartment-title{margin-top:8px;margin-bottom:8px;padding-left:32px;overflow-x:hidden;color:#404b5a}.ibo-quick-create--compartment-title>span{position:relative}.ibo-quick-create--compartment-title>span::before,.ibo-quick-create--compartment-title>span::after{content:"";display:inline-block;position:absolute;top:50%;height:1px;width:600px;border-top:1px solid #404b5a}.ibo-quick-create--compartment-title>span::before{right:100%;margin-right:8px}.ibo-quick-create--compartment-title>span::after{left:100%;margin-left:8px}.ibo-quick-create--compartment-content{color:#212934}.ibo-quick-create--compartment-element{display:flex;align-items:center;padding:4px 8px;margin-left:-8px;margin-right:-8px;color:inherit}.ibo-quick-create--compartment-element-image{margin-right:8px;width:20px}.ibo-quick-create--compartment-results--container{position:static;width:100% !important;background:transparent;border:none;box-shadow:none}.ibo-quick-create--compartment-results--element{overflow:unset;max-height:unset}.ibo-quick-create--compartment-results--element>.option{padding:4px 8px;margin-left:-8px;margin-right:-8px;color:inherit}.ibo-quick-create--compartment-results--element>.option.active{background-color:#e1e7ec;border-radius:3px}.ibo-quick-create--compartment-results--element>.option:hover{cursor:pointer;color:#9c4221;text-decoration:none}.ibo-quick-create--compartment-results--element>.option .highlight{font-weight:bold}.ibo-quick-create--compartment--placeholder{align-items:center;display:flex;flex-direction:column}.ibo-quick-create--compartment--placeholder-image>svg{width:66%;height:inherit;margin:24px auto 16px auto;display:flex}.ibo-quick-create--compartment--placeholder-hint{text-align:justify;padding:0 8px;color:#6e7a8a}@keyframes ibo-global-search--drawer--opening{from{top:-310px;box-shadow:none}to{top:100%;box-shadow:0 3px 6px rgba(0, 0, 0, 0.1), 0 10px 20px rgba(0, 0, 0, 0.15)}}.ibo-global-search{position:relative}.ibo-global-search.ibo-is-opened .ibo-global-search--input,.ibo-global-search.ibo-input-select-icon--menu .ibo-global-search--input,.ibo-global-search.ibo-is-opened .ibo-global-search--input:hover,.ibo-global-search.ibo-is-opened .ibo-global-search--input:focus,.ibo-global-search.ibo-is-opened .ibo-global-search--input:active,.ibo-global-search.ibo-input-select-icon--menu .ibo-global-search--input:hover,.ibo-global-search.ibo-input-select-icon--menu .ibo-global-search--input:focus,.ibo-global-search.ibo-input-select-icon--menu .ibo-global-search--input:active{padding:8px 8px;width:245px}.ibo-global-search.ibo-is-opened .ibo-global-search--drawer,.ibo-global-search.ibo-input-select-icon--menu .ibo-global-search--drawer{animation-name:ibo-global-search--drawer--opening;animation-delay:0.1s;animation-duration:0.2s;animation-direction:normal;animation-fill-mode:forwards}.ibo-global-search--head{background-color:white}.ibo-global-search--icon{color:#dd6c20;align-self:center;padding:0 16px}.ibo-global-search--icon:hover{color:#c05621}.ibo-global-search--icon:active{color:#9c4221}.ibo-global-search--input,.ibo-global-search--input:hover,.ibo-global-search--input:focus,.ibo-global-search--input:active{padding:0;width:0;color:#404b5a;background-color:transparent;border:none;outline:none;transition:all 0.2s ease-in-out}.ibo-global-search--input::placeholder,.ibo-global-search--input:hover::placeholder,.ibo-global-search--input:focus::placeholder,.ibo-global-search--input:active::placeholder{color:#929fb1}.ibo-global-search--input:-ms-input-placeholder,.ibo-global-search--input:hover:-ms-input-placeholder,.ibo-global-search--input:focus:-ms-input-placeholder,.ibo-global-search--input:active:-ms-input-placeholder,.ibo-global-search--input::-ms-input-placeholder,.ibo-global-search--input:hover::-ms-input-placeholder,.ibo-global-search--input:focus::-ms-input-placeholder,.ibo-global-search--input:active::-ms-input-placeholder{color:#929fb1}.ibo-global-search--drawer{z-index:-1;position:absolute;left:0;right:0;top:-310px;padding:16px 16px;background-color:white;box-shadow:none}.ibo-global-search--compartment-title{margin-bottom:8px;padding-left:32px;overflow-x:hidden;color:#404b5a}.ibo-global-search--compartment-title>span{position:relative}.ibo-global-search--compartment-title>span::before,.ibo-global-search--compartment-title>span::after{content:"";display:inline-block;position:absolute;top:50%;height:1px;width:600px;border-top:1px solid #404b5a}.ibo-global-search--compartment-title>span::before{right:100%;margin-right:8px}.ibo-global-search--compartment-title>span::after{left:100%;margin-left:8px}.ibo-global-search--compartment-content{color:#212934}.ibo-global-search--compartment-element{display:flex;align-items:center;color:inherit}.ibo-global-search--compartment-element:not(:last-child){margin-bottom:8px}.ibo-global-search--compartment-element-image{margin-right:8px;width:20px}.ibo-global-search--compartment--placeholder{align-items:center;display:flex;flex-direction:column}.ibo-global-search--compartment--placeholder-image>svg{width:66%;height:inherit;margin:24px auto 16px auto;display:flex}.ibo-global-search--compartment--placeholder-hint{text-align:justify;padding:0 8px;color:#6e7a8a}.ibo-popover-menu,.ui-menu,.ui-multiselect-menu,.ibo-input-select-icon--menu,.graph_config .toolkit_menu.graph>ul>li ul{display:none;padding:0;background-color:white;border-radius:3px;flex-wrap:wrap;position:absolute}.ibo-popover-menu.ibo-is-opened,.ibo-is-opened.ui-menu,.ui-menu.ibo-input-select-icon--menu,.ibo-is-opened.ui-multiselect-menu,.ui-multiselect-menu.ibo-input-select-icon--menu,.ibo-is-opened.ibo-input-select-icon--menu,.ibo-input-select-icon--menu,.graph_config .toolkit_menu.graph>ul>li ul.ibo-is-opened,.graph_config .toolkit_menu.graph>ul>li ul.ibo-input-select-icon--menu,.ibo-popover-menu.ibo-input-select-icon--menu,.ibo-input-select-icon--menu.ui-menu,.ibo-input-select-icon--menu.ui-multiselect-menu{display:flex;flex-direction:column}.ibo-popover-menu--toggler-visual-hint{margin-left:0.5rem}.ibo-popover-menu--section,.ui-multiselect-checkboxes{display:flex;flex-direction:column;align-self:flex-start;margin:0 0;width:100%;white-space:nowrap;overflow:hidden}.ibo-popover-menu--section:first-child,.ui-multiselect-checkboxes:first-child{border-radius:3px 3px 0 0}.ibo-popover-menu--section:last-child,.ui-multiselect-checkboxes:last-child{border-radius:0 0 3px 3px}.ibo-popover-menu--item,.ui-menu-item,.ui-multiselect-checkboxes li,.ibo-input-select-icon--menu--item,.graph_config .toolkit_menu.graph>ul>li ul li{padding:12px 24px 12px 16px;color:#212934}.ibo-popover-menu--item a,.ui-menu-item a,.ui-multiselect-checkboxes li a,.ibo-input-select-icon--menu--item a,.graph_config .toolkit_menu.graph>ul>li ul li a{color:#212934}.ibo-popover-menu--item:hover,.ui-menu-item:hover,.ui-multiselect-checkboxes li:hover,.ibo-input-select-icon--menu--item:hover,.graph_config .toolkit_menu.graph>ul>li ul li:hover{background-color:#e1e7ec;color:inherit}.ibo-popover-menu--item.ibo-popover-menu--item-separator,.ibo-popover-menu--item-separator.ui-menu-item,.ui-menu-item.ui-autocomplete-category,.ui-multiselect-checkboxes li.ibo-popover-menu--item-separator,.ui-multiselect-checkboxes li.ui-autocomplete-category,.ibo-popover-menu--item-separator.ibo-input-select-icon--menu--item,.ibo-input-select-icon--menu--item.ui-autocomplete-category,.graph_config .toolkit_menu.graph>ul>li ul li.ibo-popover-menu--item-separator,.graph_config .toolkit_menu.graph>ul>li ul li.ui-autocomplete-category,.ibo-popover-menu--item.ui-autocomplete-category,.ui-autocomplete-category.ui-menu-item,.ui-autocomplete-category.ibo-input-select-icon--menu--item{padding:0;margin:0;background-color:#e1e7ec}.ibo-popover-menu--item--icon{padding-right:5px;color:#6e7a8a;font-size:1.33rem}#ibo-navigation-menu--notifications-menu{flex-flow:column;min-width:min(550px, 90vw);max-width:90vw}#ibo-navigation-menu--notifications-menu .ibo-navigation-menu--notifications--messages-section{overflow:auto}.ibo-navigation-menu--notifications--show-all-messages,.ibo-navigation-menu--notifications-dismiss-all,.ibo-navigation-menu--notifications-show-all-multiple{overflow-x:inherit;text-align:center;min-height:45px}.ibo-navigation-menu--notifications--item--image{max-width:20px;max-height:20px;margin:0 6px;border-radius:100%}.ibo-navigation-menu--notifications--item--image[src=""]{display:none}.ibo-navigation-menu--notifications--item--image:not([src=""])~.ibo-navigation-menu--notifications--item--image{display:none}.ibo-navigation-menu--notifications--item--bottom-text{display:flex;flex-direction:column;align-items:center;float:right;align-self:center;margin-left:auto;margin-right:auto}.ibo-navigation-menu--notifications--item--content{flex-grow:1;padding:0 14px;max-height:128px;overflow-y:auto;white-space:normal}.ibo-navigation-menu--notifications--item--content img{max-height:100px;padding:5px}.ibo-navigation-menu--notifications-item{display:flex;flex-direction:row;cursor:pointer}.ibo-navigation-menu--notifications--item--new-message-indicator{width:13px;height:13px;background-color:white;border:solid 2px #aebecd;border-radius:100%;margin-top:4px;flex-shrink:0}.ibo-navigation-menu--notifications--item--new-message-indicator.ibo-is-priority-1{background-color:#fce8e8;border:solid 2px #f56565}.ibo-navigation-menu--notifications--item--new-message-indicator.ibo-is-priority-2{background-color:floralwhite;border:solid 2px #ea7d1e}.ibo-navigation-menu--notifications--item--new-message-indicator.ibo-is-priority-3{background-color:#ebf8ff;border:solid 2px #429ae1}.ibo-navigation-menu--notifications--item--new-message-indicator.ibo-is-priority-4{background-color:white;border:solid 2px #aebecd}.ibo-navigation-menu--notifications-show-all-multiple~.ibo-popover-menu .ibo-navigation-menu--notifications--item--new-message-indicator,.ibo-navigation-menu--notifications-show-all-multiple~.ui-menu .ibo-navigation-menu--notifications--item--new-message-indicator,.ibo-navigation-menu--notifications-show-all-multiple~.ui-multiselect-menu .ibo-navigation-menu--notifications--item--new-message-indicator,.ibo-navigation-menu--notifications-show-all-multiple~.ibo-input-select-icon--menu .ibo-navigation-menu--notifications--item--new-message-indicator,.graph_config .toolkit_menu.graph>ul>li .ibo-navigation-menu--notifications-show-all-multiple~ul .ibo-navigation-menu--notifications--item--new-message-indicator{display:inline-block;margin-right:15px}.ibo-navigation-menu--notifications-dismiss-all--icon{margin:0 10px 0 0}.ibo-popover-menu--item--no-message{text-align:center}.ibo-popover-menu--item--no-message--image>svg{max-width:220px;height:inherit;padding:15px}.ibo-panel.ibo-has-sticky-header>.ibo-panel--header .ibo-panel--title,.ibo-panel.ibo-has-sticky-header>.ibo-object-summary--header .ibo-panel--title,.ibo-panel.ibo-has-sticky-header>.ibo-panel--header .ibo-panel--subtitle,.ibo-panel.ibo-has-sticky-header>.ibo-object-summary--header .ibo-panel--subtitle,.ibo-panel.ibo-has-sticky-header>.ibo-panel--header .ibo-panel--icon,.ibo-panel.ibo-has-sticky-header>.ibo-object-summary--header .ibo-panel--icon,.ibo-panel.ibo-has-sticky-header>.ibo-panel--header .ibo-panel--titles,.ibo-panel.ibo-has-sticky-header>.ibo-object-summary--header .ibo-panel--titles,.ibo-object-details.ibo-has-sticky-header>.ibo-panel--header .ibo-panel--header-left,.ibo-object-details.ibo-has-sticky-header>.ibo-object-summary--header .ibo-panel--header-left{transition:all 0.15s linear}.ibo-panel{--ibo-main-color: #929fb1;position:relative}.ibo-panel.ibo-has-icon>.ibo-panel--header .ibo-panel--titles,.ibo-panel.ibo-has-icon>.ibo-object-summary--header .ibo-panel--titles{padding-left:16px}.ibo-panel.ibo-has-icon.ibo-has-medallion-icon>.ibo-panel--header .ibo-panel--header-left,.ibo-panel.ibo-has-icon.ibo-has-medallion-icon>.ibo-object-summary--header .ibo-panel--header-left{position:relative;z-index:1;margin-left:16px}.ibo-panel.ibo-has-icon.ibo-has-medallion-icon>.ibo-panel--header .ibo-panel--header-left .ibo-panel--icon,.ibo-panel.ibo-has-icon.ibo-has-medallion-icon>.ibo-object-summary--header .ibo-panel--header-left .ibo-panel--icon{position:absolute;bottom:-24px;left:0;overflow:hidden;width:72px;height:72px;min-width:72px;min-height:72px;background-color:#f8f9fa;border:2px solid #90a4ae;border-radius:100%}.ibo-panel.ibo-has-icon.ibo-has-medallion-icon>.ibo-panel--header .ibo-panel--header-left .ibo-panel--titles,.ibo-panel.ibo-has-icon.ibo-has-medallion-icon>.ibo-object-summary--header .ibo-panel--header-left .ibo-panel--titles{padding-left:calc(72px + 16px)}.ibo-panel.ibo-is-selectable .ibo-panel--body::after{content:" ";background-color:transparent;cursor:pointer;position:absolute;display:flex;align-items:center;justify-content:center;height:100%;width:100%;z-index:3;font-size:7rem}.ibo-panel.ibo-is-selectable:hover .ibo-panel--body::after{content:"";color:#f8f9fa;background-color:rgba(146, 159, 177, 0.4);display:flex}.ibo-panel.ibo-is-selected .ibo-panel--body::after{content:"";color:#f8f9fa;background-color:rgba(33, 41, 52, 0.5);display:flex}.ibo-panel.ibo-is-selected:hover .ibo-panel--body::after{background-color:rgba(110, 122, 138, 0.5);display:flex}.ibo-panel--header,.ibo-object-summary--header{position:relative;z-index:2;display:flex;justify-content:space-between;align-items:flex-end;margin-bottom:4px}.ibo-panel--header-left{justify-content:left}.ibo-panel--icon{width:48px;height:48px;min-width:48px;min-height:48px}.ibo-panel--icon-img,.ibo-panel--icon-background{width:100%;height:100%;object-position:center;object-fit:contain;background-position:center;background-repeat:no-repeat;background-size:contain}.ibo-panel--icon-img--must-contain,.ibo-panel--icon-background--must-contain{object-fit:contain;background-size:contain}.ibo-panel--icon-img--must-cover,.ibo-panel--icon-background--must-cover{object-fit:cover;background-size:cover}.ibo-panel--icon-img--must-zoomout,.ibo-panel--icon-background--must-zoomout{width:66.67%;height:66.67%}.ibo-panel--title{display:inline-block;color:#212934;flex-grow:1}.ibo-panel--subtitle{display:flex;color:#404b5a}.ibo-panel--body{position:relative;z-index:1;padding:32px 16px 24px 16px;background-color:white;border:1px solid #ccd4db;border-radius:5px;overflow:hidden}.ibo-panel--body::before{position:absolute;top:0;left:0;display:block;background-color:var(--ibo-main-color);content:"";width:100%;height:8px;padding-bottom:8px}.ibo-panel.ibo-is-primary>.ibo-panel--body::before{background-color:#dd6c20}.ibo-panel.ibo-is-secondary>.ibo-panel--body::before,.ui-dialog .ibo-panel.ui-button>.ibo-panel--body::before,.ibo-panel.ui-datepicker-current>.ibo-panel--body::before,.ibo-panel.ui-datepicker-close>.ibo-panel--body::before{background-color:#929fb1}.ibo-panel.ibo-is-neutral>.ibo-panel--body::before,.ui-dialog .ibo-panel.ui-button.ui-dialog-titlebar-close>.ibo-panel--body::before{background-color:#929fb1}.ibo-panel.ibo-is-information>.ibo-panel--body::before{background-color:#3182ce}.ibo-panel.ibo-is-success>.ibo-panel--body::before{background-color:#7cb342}.ibo-panel.ibo-is-failure>.ibo-panel--body::before{background-color:#e53e3e}.ibo-panel.ibo-is-warning>.ibo-panel--body::before{background-color:#dd6c20}.ibo-panel.ibo-is-danger>.ibo-panel--body::before{background-color:#e53e3e}.ibo-panel.ibo-is-grey>.ibo-panel--body::before{background-color:#929fb1}.ibo-panel.ibo-is-blue-grey>.ibo-panel--body::before{background-color:#546e7a}.ibo-panel.ibo-is-blue>.ibo-panel--body::before{background-color:#2c5382}.ibo-panel.ibo-is-cyan>.ibo-panel--body::before{background-color:#00aac1}.ibo-panel.ibo-is-green>.ibo-panel--body::before{background-color:#7cb342}.ibo-panel.ibo-is-orange>.ibo-panel--body::before{background-color:#dd6c20}.ibo-panel.ibo-is-red>.ibo-panel--body::before{background-color:#e53e3e}.ibo-panel.ibo-is-pink>.ibo-panel--body::before{background-color:#d53f8c}.ibo-panel--collapsible-toggler{display:inline-block;margin-right:8px;font-size:1.5rem;color:#6e7a8a;cursor:pointer}.ibo-panel .ibo-panel--collapsible-toggler--opened{display:block}.ibo-panel .ibo-panel--collapsible-toggler--closed{display:none}.ibo-panel:not(.ibo-is-opened) .ibo-panel--collapsible-toggler--closed{display:block}.ibo-panel:not(.ibo-is-opened) .ibo-panel--collapsible-toggler--opened{display:none}.ibo-panel:not(.ibo-is-opened) .ibo-panel--body{display:none}.ibo-panel.ibo-has-sticky-header>.ibo-panel--header,.ibo-panel.ibo-has-sticky-header>.ibo-object-summary--header{position:sticky;top:0;border:transparent;transition-property:all, top, background-color;transition-duration:0.15s, 0s, 0s;transition-timing-function:linear}.ibo-panel.ibo-has-sticky-header>.ibo-panel--header.ibo-is-sticking,.ibo-panel.ibo-has-sticky-header>.ibo-is-sticking.ibo-object-summary--header{padding-top:4px;padding-bottom:4px;background-color:#f8f9fa;border:1px solid #ccd4db;align-items:center}.ibo-panel.ibo-has-sticky-header>.ibo-panel--header.ibo-is-sticking .ibo-panel--title,.ibo-panel.ibo-has-sticky-header>.ibo-is-sticking.ibo-object-summary--header .ibo-panel--title{font-size:1.17rem}.ibo-panel.ibo-has-sticky-header>.ibo-panel--header.ibo-is-sticking .ibo-panel--subtitle,.ibo-panel.ibo-has-sticky-header>.ibo-is-sticking.ibo-object-summary--header .ibo-panel--subtitle{font-size:1rem}.ibo-panel.ibo-has-sticky-header.ibo-has-icon.ibo-has-medallion-icon>.ibo-panel--header,.ibo-panel.ibo-has-sticky-header.ibo-has-icon.ibo-has-medallion-icon>.ibo-object-summary--header{}.ibo-panel.ibo-has-sticky-header.ibo-has-icon.ibo-has-medallion-icon>.ibo-panel--header.ibo-is-sticking .ibo-panel--icon,.ibo-panel.ibo-has-sticky-header.ibo-has-icon.ibo-has-medallion-icon>.ibo-is-sticking.ibo-object-summary--header .ibo-panel--icon{bottom:-12px;width:48px;height:48px;min-width:48px;min-height:48px;border:1px solid #ccd4db}.ibo-panel.ibo-has-sticky-header.ibo-has-icon.ibo-has-medallion-icon>.ibo-panel--header.ibo-is-sticking .ibo-panel--titles,.ibo-panel.ibo-has-sticky-header.ibo-has-icon.ibo-has-medallion-icon>.ibo-is-sticking.ibo-object-summary--header .ibo-panel--titles{padding-left:calc(48px + 16px)}.ibo-collapsible-section--header{display:flex;align-items:stretch}.ibo-collapsible-section.ibo-is-opened .ibo-collapsible-section--minimize-button,.ibo-collapsible-section.ibo-input-select-icon--menu .ibo-collapsible-section--minimize-button{display:block}.ibo-collapsible-section.ibo-is-opened .ibo-collapsible-section--maximize-button,.ibo-collapsible-section.ibo-input-select-icon--menu .ibo-collapsible-section--maximize-button{display:none}.ibo-collapsible-section:not(.ibo-is-opened) .ibo-collapsible-section--minimize-button{display:none}.ibo-collapsible-section:not(.ibo-is-opened) .ibo-collapsible-section--maximize-button{display:block}.ibo-collapsible-section:not(.ibo-is-opened) .ibo-collapsible-section--body{display:none}.ibo-collapsible-section .ibo-collapsible-section--header{cursor:pointer}.ibo-collapsible-section .ibo-collapsible-section--header:hover i{opacity:0.8}.ibo-collapsible-section .ibo-collapsible-section--header .ibo-collapsible-section--action-button{align-self:center}.ibo-collapsible-section .ibo-collapsible-section--header .ibo-collapsible-section--action-button.ibo-collapsible-section--maximize-button,.ibo-collapsible-section .ibo-collapsible-section--header .ibo-collapsible-section--action-button.ibo-collapsible-section--minimize-button{color:#6e7a8a;margin-right:8px}.ibo-collapsible-section .ibo-collapsible-section--header .ibo-collapsible-section--title{color:#212934;flex-grow:1}.ibo-collapsible-section .ibo-collapsible-section--body{position:relative;padding:24px 16px 16px;background-color:white;border:solid 1px #ccd4db;border-radius:5px;overflow:hidden}.ibo-modal{display:flex;flex-direction:column;max-height:90vh !important;max-width:90vw !important}.ibo-modal.ibo-is-extra-small{height:calc(min(20vh, 150px)) !important;width:calc(min(20vw, 200px)) !important}.ibo-modal.ibo-is-small{height:calc(min(60vh, 400px)) !important;width:calc(min(60vw, 800px)) !important}.ibo-modal.ibo-is-medium{height:calc(min(75vh, 600px)) !important;width:calc(min(75vw, 1200px)) !important}.ibo-modal.ibo-is-large{height:calc(min(90vh, 900px)) !important;width:calc(min(90vw, 1800px)) !important}.ibo-modal-option--do-not-show-again{margin-top:16px}.ibo-modal-option--do-not-show-again .ibo-modal-option--do-not-show-again--checkbox{height:auto;display:inline-block;width:auto}.ibo-modal.ibo-is-informative{align-items:center;min-width:384px;min-height:24px !important}.ibo-modal.ibo-is-informative::before{display:block;position:absolute;top:0;left:0;content:"";width:4px;height:100%}.ibo-modal.ibo-is-informative.ibo-is-error::before{background-color:#e53e3e}.ibo-modal.ibo-is-informative.ibo-is-warning::before{background-color:#dd6c20}.ibo-modal.ibo-is-informative.ibo-is-information::before{background-color:#3182ce}.ibo-modal.ibo-is-informative.ibo-is-success::before{background-color:#7cb342}.ibo-dashlet{position:relative;width:calc(100% - 24px);margin:calc(24px / 2) calc(24px / 2)}.ibo-dashlet.dashlet-selected{position:relative}.ibo-dashlet--is-inline{width:auto}.ibo-dashlet-blocker{position:absolute;z-index:9;top:0;left:0;width:100%;height:100%;cursor:not-allowed}:root{--ibo-dashlet-badge--min-width: 200px;--ibo-dashlet-badge--padding-x: 16px;--ibo-dashlet-badge--padding-y: 16px;--ibo-dashlet-badge--background-color: white;--ibo-dashlet-badge--border: 1px solid #ccd4db;--ibo-dashlet-badge--border-radius: 5px}.ibo-dashlet-badge{max-width:350px;flex-basis:200px;flex-grow:1;flex-shrink:1;padding:16px 16px;background-color:white;border:1px solid #ccd4db;border-radius:5px}.ibo-dashlet-badge--body{display:flex;justify-items:left;align-items:center}.ibo-dashlet-badge--icon-container{margin-right:16px}.ibo-dashlet-badge--icon{width:48px;min-width:48px;max-height:48px}.ibo-dashlet-badge--actions{flex-grow:1;overflow-x:hidden}.ibo-dashlet-badge--action-list{color:inherit}.ibo-dashlet-badge--action-list-count{margin-right:8px}.ibo-dashlet-badge--action-list-label{display:inline-block}.ibo-dashlet-badge--action-create-icon{margin-right:8px}.ibo-dashlet-badge--body--tooltip-title{margin-bottom:16px}.ibo-dashlet-header-static{padding:16px 16px 0 16px;overflow-x:hidden}.ibo-dashlet-header-static--body{position:relative;display:inline-flex;justify-items:left;align-items:center;margin-left:48px;color:#212934}.ibo-dashlet-header-static--body::before,.ibo-dashlet-header-static--body::after{content:"";position:absolute;top:50%;width:10000px;height:1px;border-bottom:2px solid #ccd4db}.ibo-dashlet-header-static--body::before{right:calc(100% + 16px)}.ibo-dashlet-header-static--body::after{left:calc(100% + 16px)}.ibo-dashlet-header-static--icon-container{margin-right:16px}.ibo-dashlet-header-static--icon{width:48px;min-width:48px;max-height:48px}.ibo-dashlet-header-dynamic--container{display:flex;flex-wrap:wrap}.ibo-dashlet-header-dynamic--count{margin-right:10px}.ibo-input,.ui-autocomplete-input,.ui-multiselect,.dataTables_length select,.ui_tpicker_hour_slider>select,.ui_tpicker_minute_slider>select,.ui_tpicker_second_slider>select,select.ibo-input-select-placeholder,.ibo-datatableconfig--attributes-panel--per-page--input,.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content input[type="text"],.search_form_handler .sf_filter .sff_input_wrapper input[type="text"]{height:30px;width:100%;background-color:white;color:#212934;padding:0 10px;border:1px solid #aebecd;border-radius:3px}.ibo-input:focus,.ui-autocomplete-input:focus,.ui-multiselect:focus,.dataTables_length select:focus,.ui_tpicker_hour_slider>select:focus,.ui_tpicker_minute_slider>select:focus,.ui_tpicker_second_slider>select:focus,select.ibo-input-select-placeholder:focus,.ibo-datatableconfig--attributes-panel--per-page--input:focus,.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content input[type="text"]:focus,.search_form_handler .sf_filter .sff_input_wrapper input[type="text"]:focus{border-color:#dd6c20}.ibo-input:disabled,.ui-autocomplete-input:disabled,.ui-multiselect:disabled,.dataTables_length select:disabled,.ui_tpicker_hour_slider>select:disabled,.ui_tpicker_minute_slider>select:disabled,.ui_tpicker_second_slider>select:disabled,select.ibo-input-select-placeholder:disabled,.ibo-datatableconfig--attributes-panel--per-page--input:disabled,.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content input[type="text"]:disabled,.search_form_handler .sf_filter .sff_input_wrapper input[type="text"]:disabled{background-color:#d5dde5;color:#929fb1}.ibo-input::placeholder,.ui-autocomplete-input::placeholder,.ui-multiselect::placeholder,.dataTables_length select::placeholder,.ui_tpicker_hour_slider>select::placeholder,.ui_tpicker_minute_slider>select::placeholder,.ui_tpicker_second_slider>select::placeholder,select.ibo-input-select-placeholder::placeholder,.ibo-datatableconfig--attributes-panel--per-page--input::placeholder,.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content input[type="text"]::placeholder,.search_form_handler .sf_filter .sff_input_wrapper input[type="text"]::placeholder{color:#929fb1}textarea.ibo-input,textarea.ui-autocomplete-input,textarea.ui-multiselect,textarea.ibo-datatableconfig--attributes-panel--per-page--input{height:unset}.ibo-input-wrapper.is-error .ibo-input,.is-error.ui_tpicker_hour_slider .ibo-input,.is-error.ui_tpicker_hour_slider .ui-autocomplete-input,.is-error.ui_tpicker_hour_slider .ui-multiselect,.is-error.ui_tpicker_hour_slider .dataTables_length select,.dataTables_length .is-error.ui_tpicker_hour_slider select,.is-error.ui_tpicker_hour_slider .ui_tpicker_hour_slider>select,.is-error.ui_tpicker_hour_slider .ui_tpicker_minute_slider>select,.is-error.ui_tpicker_hour_slider .ui_tpicker_second_slider>select,.is-error.ui_tpicker_hour_slider select.ibo-input-select-placeholder,.is-error.ui_tpicker_hour_slider .ibo-datatableconfig--attributes-panel--per-page--input,.is-error.ui_tpicker_hour_slider .search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content input[type="text"],.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content .is-error.ui_tpicker_hour_slider input[type="text"],.is-error.ui_tpicker_hour_slider .search_form_handler .sf_filter .sff_input_wrapper input[type="text"],.search_form_handler .sf_filter .sff_input_wrapper .is-error.ui_tpicker_hour_slider input[type="text"],.is-error.ui_tpicker_minute_slider .ibo-input,.is-error.ui_tpicker_minute_slider .ui-autocomplete-input,.is-error.ui_tpicker_minute_slider .ui-multiselect,.is-error.ui_tpicker_minute_slider .dataTables_length select,.dataTables_length .is-error.ui_tpicker_minute_slider select,.is-error.ui_tpicker_minute_slider .ui_tpicker_hour_slider>select,.is-error.ui_tpicker_minute_slider .ui_tpicker_minute_slider>select,.is-error.ui_tpicker_minute_slider .ui_tpicker_second_slider>select,.is-error.ui_tpicker_minute_slider select.ibo-input-select-placeholder,.is-error.ui_tpicker_minute_slider .ibo-datatableconfig--attributes-panel--per-page--input,.is-error.ui_tpicker_minute_slider .search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content input[type="text"],.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content .is-error.ui_tpicker_minute_slider input[type="text"],.is-error.ui_tpicker_minute_slider .search_form_handler .sf_filter .sff_input_wrapper input[type="text"],.search_form_handler .sf_filter .sff_input_wrapper .is-error.ui_tpicker_minute_slider input[type="text"],.is-error.ui_tpicker_second_slider .ibo-input,.is-error.ui_tpicker_second_slider .ui-autocomplete-input,.is-error.ui_tpicker_second_slider .ui-multiselect,.is-error.ui_tpicker_second_slider .dataTables_length select,.dataTables_length .is-error.ui_tpicker_second_slider select,.is-error.ui_tpicker_second_slider .ui_tpicker_hour_slider>select,.is-error.ui_tpicker_second_slider .ui_tpicker_minute_slider>select,.is-error.ui_tpicker_second_slider .ui_tpicker_second_slider>select,.is-error.ui_tpicker_second_slider select.ibo-input-select-placeholder,.is-error.ui_tpicker_second_slider .ibo-datatableconfig--attributes-panel--per-page--input,.is-error.ui_tpicker_second_slider .search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content input[type="text"],.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content .is-error.ui_tpicker_second_slider input[type="text"],.is-error.ui_tpicker_second_slider .search_form_handler .sf_filter .sff_input_wrapper input[type="text"],.search_form_handler .sf_filter .sff_input_wrapper .is-error.ui_tpicker_second_slider input[type="text"],.ibo-input-wrapper.is-error .ui-autocomplete-input,.ibo-input-wrapper.is-error .ui-multiselect,.ibo-input-wrapper.is-error .dataTables_length select,.dataTables_length .ibo-input-wrapper.is-error select,.ibo-input-wrapper.is-error .ui_tpicker_hour_slider>select,.ibo-input-wrapper.is-error .ui_tpicker_minute_slider>select,.ibo-input-wrapper.is-error .ui_tpicker_second_slider>select,.ibo-input-wrapper.is-error select.ibo-input-select-placeholder,.ibo-input-wrapper.is-error .ibo-datatableconfig--attributes-panel--per-page--input,.ibo-input-wrapper.is-error .search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content input[type="text"],.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content .ibo-input-wrapper.is-error input[type="text"],.ibo-input-wrapper.is-error .search_form_handler .sf_filter .sff_input_wrapper input[type="text"],.search_form_handler .sf_filter .sff_input_wrapper .ibo-input-wrapper.is-error input[type="text"],.ibo-input-wrapper.is-error .ibo-input-vanilla,.is-error.ui_tpicker_hour_slider .ibo-input-vanilla,.is-error.ui_tpicker_minute_slider .ibo-input-vanilla,.is-error.ui_tpicker_second_slider .ibo-input-vanilla,.ibo-input-wrapper.is-error .ck-editor,.is-error.ui_tpicker_hour_slider .ck-editor,.is-error.ui_tpicker_minute_slider .ck-editor,.is-error.ui_tpicker_second_slider .ck-editor,.ibo-input-wrapper.is-error textarea,.is-error.ui_tpicker_hour_slider textarea,.is-error.ui_tpicker_minute_slider textarea,.is-error.ui_tpicker_second_slider textarea,.ibo-input-field-wrapper.is-error .ibo-input,.ibo-input-field-wrapper.is-error .ui-autocomplete-input,.ibo-input-field-wrapper.is-error .ui-multiselect,.ibo-input-field-wrapper.is-error .dataTables_length select,.dataTables_length .ibo-input-field-wrapper.is-error select,.ibo-input-field-wrapper.is-error .ui_tpicker_hour_slider>select,.ibo-input-field-wrapper.is-error .ui_tpicker_minute_slider>select,.ibo-input-field-wrapper.is-error .ui_tpicker_second_slider>select,.ibo-input-field-wrapper.is-error select.ibo-input-select-placeholder,.ibo-input-field-wrapper.is-error .ibo-datatableconfig--attributes-panel--per-page--input,.ibo-input-field-wrapper.is-error .search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content input[type="text"],.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content .ibo-input-field-wrapper.is-error input[type="text"],.ibo-input-field-wrapper.is-error .search_form_handler .sf_filter .sff_input_wrapper input[type="text"],.search_form_handler .sf_filter .sff_input_wrapper .ibo-input-field-wrapper.is-error input[type="text"],.ibo-input-field-wrapper.is-error .ibo-input-vanilla,.ibo-input-field-wrapper.is-error .ck-editor,.ibo-input-field-wrapper.is-error textarea{border-color:#e53e3e}.ibo-input-wrapper.is-error .ibo-input-vanilla input,.is-error.ui_tpicker_hour_slider .ibo-input-vanilla input,.is-error.ui_tpicker_minute_slider .ibo-input-vanilla input,.is-error.ui_tpicker_second_slider .ibo-input-vanilla input,.ibo-input-field-wrapper.is-error .ibo-input-vanilla input{border:0;background-color:rgba(255, 255, 255, 0)}input.ibo-input-vanilla{width:unset;display:initial}.ibo-input-wrapper--with-buttons,.ibo-input-select-wrapper--with-buttons{position:relative;display:flex}.ibo-field-validation{color:#c53030}.file-input{display:block;position:relative}.ibo-input--label-right{margin-right:4px;display:inline}.ibo-input--label-left{margin-left:4px;display:inline}.disabled{background-color:#d5dde5}.ibo-input-checkbox{height:16px;width:auto}.ibo-input-date-wrapper{position:relative}.ibo-input-date{display:inline-block;width:100%}.ibo-input-date+button{position:absolute;display:inline-block;margin-left:-20px;margin-top:5px;padding:0;background-color:transparent;color:#404b5a;border:none}.ibo-input-datetime-wrapper{position:relative}.ibo-input-datetime{display:inline-block;width:100%}.ibo-input-datetime--action-button{position:absolute;display:inline-block;margin-left:-20px;margin-top:5px;padding:0;color:#404b5a}.ui_tpicker_hour_slider>select,.ui_tpicker_minute_slider>select,.ui_tpicker_second_slider>select{width:auto;padding-right:18px}.ibo-input-duration{display:inline-block;width:unset;text-align:right}.ibo-input-image{display:flex;justify-content:flex-start;align-items:flex-start}.ibo-input-image--image-view{position:relative;overflow:hidden;min-height:96px;background-color:#e1e7ec;border-radius:5px}.ibo-input-image--image-view img[src=""],.ibo-input-image--image-view img[src="null"]{visibility:hidden}.ibo-input-image--image-view input[type="file"]{position:absolute;top:0;bottom:0;left:0;right:0;width:100%;opacity:0}.ibo-input-image--edit-buttons{display:flex;flex-direction:column;margin-left:0.5rem}.ibo-input-image--edit-buttons .ibo-button+.ibo-button,.ibo-input-image--edit-buttons .ui-dialog .ui-button+.ibo-button,.ibo-input-image--edit-buttons .ui-dialog .ui-dialog .ui-button+.ui-button,.ui-dialog .ibo-input-image--edit-buttons .ui-dialog .ui-button+.ui-button,.ibo-input-image--edit-buttons .ui-dialog .ui-button+.ui-datepicker-current,.ibo-input-image--edit-buttons .ui-dialog .ui-button+.ui-datepicker-close,.ui-dialog .ibo-input-image--edit-buttons .ui-button+.ibo-button,.ibo-input-image--edit-buttons .ui-datepicker-current+.ibo-button,.ibo-input-image--edit-buttons .ui-dialog .ui-datepicker-current+.ui-button,.ui-dialog .ibo-input-image--edit-buttons .ui-datepicker-current+.ui-button,.ibo-input-image--edit-buttons .ui-datepicker-current+.ui-datepicker-current,.ibo-input-image--edit-buttons .ui-datepicker-current+.ui-datepicker-close,.ibo-input-image--edit-buttons .ui-datepicker-close+.ibo-button,.ibo-input-image--edit-buttons .ui-dialog .ui-datepicker-close+.ui-button,.ui-dialog .ibo-input-image--edit-buttons .ui-datepicker-close+.ui-button,.ibo-input-image--edit-buttons .ui-datepicker-close+.ui-datepicker-current,.ibo-input-image--edit-buttons .ui-datepicker-close+.ui-datepicker-close,.ibo-input-image--edit-buttons .ui-dialog .ibo-button+.ui-button,.ui-dialog .ibo-input-image--edit-buttons .ibo-button+.ui-button,.ibo-input-image--edit-buttons .ibo-button+.ui-datepicker-current,.ibo-input-image--edit-buttons .ibo-button+.ui-datepicker-close{margin-top:0.5rem;margin-left:0}.ibo-input-richtext-placeholder{height:192px;width:100%;visibility:hidden}.ibo-input-select,.ui-multiselect,.ui_tpicker_hour_slider>select,.ui_tpicker_minute_slider>select,.ui_tpicker_second_slider>select,select.ibo-input-select-placeholder{display:inline-flex;min-width:50px;appearance:none}.ibo-input-select.ibo-input-selectize,.ibo-input-selectize.ui-multiselect,.ui_tpicker_hour_slider>select.ibo-input-selectize,.ui_tpicker_minute_slider>select.ibo-input-selectize,.ui_tpicker_second_slider>select.ibo-input-selectize,select.ibo-input-selectize.ibo-input-select-placeholder{padding-right:0;padding-left:0;min-width:150px !important}.ibo-input-select.ibo-input-selectize input,.ibo-input-selectize.ui-multiselect input,.ui_tpicker_hour_slider>select.ibo-input-selectize input,.ui_tpicker_minute_slider>select.ibo-input-selectize input,.ui_tpicker_second_slider>select.ibo-input-selectize input,select.ibo-input-selectize.ibo-input-select-placeholder input{border-width:0;color:inherit;border-color:white;padding-left:10px}.ibo-input-select.ibo-input-selectize>[data-value],.ibo-input-selectize.ui-multiselect>[data-value],.ui_tpicker_hour_slider>select.ibo-input-selectize>[data-value],.ui_tpicker_minute_slider>select.ibo-input-selectize>[data-value],.ui_tpicker_second_slider>select.ibo-input-selectize>[data-value],select.ibo-input-selectize.ibo-input-select-placeholder>[data-value]{height:100%;line-height:30px;padding-left:10px}.ibo-input-select[size],.ui-multiselect[size],.ui_tpicker_hour_slider>select[size],.ui_tpicker_minute_slider>select[size],.ui_tpicker_second_slider>select[size],select.ibo-input-select-placeholder[size]{height:auto}.ibo-input-select[multiple],.ui-multiselect[multiple],.ui_tpicker_hour_slider>select[multiple],.ui_tpicker_minute_slider>select[multiple],.ui_tpicker_second_slider>select[multiple],select.ibo-input-select-placeholder[multiple]{padding-left:unset;padding-right:unset}.ibo-input-select[multiple] option,.ui-multiselect[multiple] option,.ui_tpicker_hour_slider>select[multiple] option,.ui_tpicker_minute_slider>select[multiple] option,.ui_tpicker_second_slider>select[multiple] option,select.ibo-input-select-placeholder[multiple] option{padding:4px 10px}.ibo-input-select-autocomplete{min-width:150px !important;text-overflow:ellipsis}.ibo-input-selectize{min-width:150px !important}.ibo-input-selectize>div{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ibo-input-selectize>input{background-color:unset;border:unset}.ibo-input-selectize>input:focus{outline:none !important}.ibo-input-selectize.input-active{border:1px solid #dd6c20}.ibo-input-select-wrapper,.ui_tpicker_hour_slider,.ui_tpicker_minute_slider,.ui_tpicker_second_slider{position:relative}.ibo-input-select-wrapper--with-buttons .selectize-control{display:grid;width:100%}.ibo-input-select-wrapper::after,.ui_tpicker_hour_slider::after,.ui_tpicker_minute_slider::after,.ui_tpicker_second_slider::after{position:absolute;z-index:1;content:"";font-family:"Font Awesome 5 Free";font-weight:600;height:28px;margin-left:-16px;margin-top:1px;padding-top:3px;background-color:inherit;color:#212934;pointer-events:none}.ibo-input-select-container{display:flex}.ibo-input-select-wrapper--with-buttons:not(.ibo-input-select-autocomplete-wrapper)::after{position:absolute;z-index:1;content:"";font-family:"Font Awesome 5 Free";font-weight:600;cursor:pointer;right:8px;height:28px;margin-left:-16px;margin-top:1px;padding-top:3px;background-color:inherit;color:#212934;pointer-events:none}.ibo-input-select--action-buttons{position:absolute;z-index:1;display:flex;height:28px;margin-top:0;margin-right:3px;font-size:1rem;background-color:inherit;color:#404b5a;padding:0 2px;text-align:right;bottom:0;top:0;right:0}.ibo-input-select-wrapper .ibo-input-select--action-buttons,.ui_tpicker_hour_slider .ibo-input-select--action-buttons,.ui_tpicker_minute_slider .ibo-input-select--action-buttons,.ui_tpicker_second_slider .ibo-input-select--action-buttons{margin-right:20px}.ibo-input-select--action-button{display:flex;align-items:center;padding-left:6px;padding-right:2px;float:right}.selectize-dropdown.ui-autocomplete,.selectize-dropdown.set-dropdown,.selectize-dropdown.plugin-custom_itop{z-index:2000;max-height:50vh;max-width:50em;overflow-y:auto}.selectize-dropdown-content{max-height:calc(50vh - 4px)}.selectize-dropdown.ui-menu .ui-state-active{margin:unset;background-color:#ebf8ff;color:#404b5a}.ibo-input-select--autocomplete-item,.ibo-input-select--notification-item{display:flex;justify-content:left;align-items:center}.ibo-input-select--autocomplete-item-image{width:30px;height:30px;min-width:30px;min-height:30px;background-position:center center;background-size:100%;border-radius:100%;margin-right:0.7rem;background-color:#ebf8ff;border:1px solid #929fb1}.ibo-input-select--autocomplete-item-image.ibo-is-not-medallion{border:unset;border-radius:0;background-color:unset}.ibo-input-select-icon{display:inline-flex;text-align:left}.ibo-input-select-icon>img{max-height:100%;max-width:100%;padding-right:4px}.ibo-input-select-icon>span{overflow:hidden}.ibo-input-select-icon--menu{position:absolute;z-index:21;max-height:300px;overflow-x:hidden;overflow-y:auto;flex-wrap:nowrap}.ibo-input-select-icon--menu--item>*{width:100%;white-space:nowrap;overflow-x:hidden;text-overflow:ellipsis}.ibo-input-select-icon--menu--item>*>.ibo-input-select-icon--menu--icon{max-width:100%;max-height:100%;margin-right:10px}.ibo-input-one-way-password-wrapper>*:not(first-child){margin-top:6px}.ibo-input-set{flex-wrap:wrap;height:auto;min-height:30px}.ibo-input-set>input{height:auto}.ibo-input-set .item[data-value]>.remove{font-size:18px;padding-top:0.15em;border-left:none}.attribute-set .attribute-set-item,.selectize-control.multi .selectize-input.ibo-input-set .attribute-set-item,.selectize-control.multi .ibo-quick-create--input.selectize-control.single .ibo-input-set.selectize-input.input-active .attribute-set-item,.ibo-quick-create--input.selectize-control.single .selectize-control.multi .ibo-input-set.selectize-input.input-active .attribute-set-item{display:inline-flex;margin-top:1px;margin-right:0;margin-bottom:1px;padding:4px 6px;max-width:360px;background:white none;border:none;border-radius:3px;box-shadow:0 1px 1px rgba(0, 0, 0, 0.15), 0 0 1px 1px rgba(241, 241, 241, 0.7);color:#212934;text-shadow:none}.attribute-set .attribute-set-item:not(:first-child),.selectize-control.multi .selectize-input.ibo-input-set .attribute-set-item:not(:first-child),.selectize-control.multi .ibo-quick-create--input.selectize-control.single .ibo-input-set.selectize-input.input-active .attribute-set-item:not(:first-child),.ibo-quick-create--input.selectize-control.single .selectize-control.multi .ibo-input-set.selectize-input.input-active .attribute-set-item:not(:first-child){margin-left:3px}.attribute-set.history-added .attribute-set-item{font-weight:bold}.attribute-set.history-removed .attribute-set-item{text-decoration:line-through;font-style:italic}.selectize-control.multi .selectize-input.ibo-input-set,.selectize-control.multi .ibo-quick-create--input.selectize-control.single .ibo-input-set.selectize-input.input-active,.ibo-quick-create--input.selectize-control.single .selectize-control.multi .ibo-input-set.selectize-input.input-active{padding:0 8px}.ibo-input-text,textarea{width:100%;min-height:12rem;padding:10px 12px}.ibo-input-text.ibo-is-code,textarea.ibo-is-code{background-color:white}.ibo-input-text--export{width:100%;min-height:15em}.ibo-toggler--wrapper{position:relative;display:inline-block;width:36px;height:20px;vertical-align:baseline}.ibo-toggler--wrapper .ibo-toggler{display:none}.ibo-toggler--slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;border-radius:16px;background-color:#929fb1;transition:0.4s}.ibo-toggler--slider:before{content:"";position:absolute;left:3px;bottom:3px;height:15px;width:15px;border-radius:100%;background-color:#f8f9fa;transition:0.4s}.ibo-toggler--wrapper input:checked+.ibo-toggler--slider{background-color:#dd6c20}input:focus+.ibo-toggler--slider{box-shadow:0 0 1px #dd6c20}input:checked+.ibo-toggler--slider:before{transform:translateX(14.5px)}label~.ibo-toggler--wrapper{margin-left:4px}.ibo-pill.ibo-is-new{color:#2a4265;background-color:#ebf8ff}.ibo-pill.ibo-is-neutral,.ui-dialog .ibo-pill.ui-button.ui-dialog-titlebar-close{color:#2a4265;background-color:#ebf8ff}.ibo-pill.ibo-is-waiting{color:#9c4221;background-color:floralwhite}.ibo-pill.ibo-is-success{color:#33691e;background-color:#dcedc8}.ibo-pill.ibo-is-failure{color:#9b2c2c;background-color:#fce8e8}.ibo-pill.ibo-is-frozen{color:#6e7a8a;background-color:#f8f9fa}.ibo-pill.ibo-is-active{color:#33691e;background-color:#dcedc8}.ibo-pill.ibo-is-inactive{color:#9c4221;background-color:floralwhite}.ibo-pill{--ibo-main-color--100: #ebf8ff;--ibo-main-color--900: #2a4265;max-width:240px;margin-top:4px;margin-bottom:4px;padding:6px 10px;border-radius:3px;color:var(--ibo-main-color--900);background-color:var(--ibo-main-color--100)}.ibo-pill:hover,.ibo-pill:active{color:inherit}.ibo-prop--apply{width:calc(32px + 12px);padding-left:12px}.ibo-prop--apply.ui-state-error:after{color:#404b5a;content:"";vertical-align:bottom}.ibo-prop--apply.ui-state-error>span{display:none !important}.ibo-prop--cancel{width:calc(32px + 8px);padding-left:8px}.ibo-prop--apply,.ibo-prop--cancel{height:28px}.ibo-prop--apply>span,.ibo-prop--cancel>span{display:block;height:28px;width:32px;text-align:center}.ibo-prop--apply>span>div,.ibo-prop--cancel>span>div{display:inline-flex;justify-content:center;align-items:center;width:100%;height:100%}.ibo-spinner.ibo-is-inline{display:inline-block}.ibo-spinner.ibo-is-inline>*{display:inline-block}.ibo-spinner.ibo-is-small,.ibo-spinner.ibo-is-medium,.ibo-spinner.ibo-is-large{display:flex;flex-direction:column}.ibo-spinner.ibo-is-small>.ibo-spinner--icon,.ibo-spinner.ibo-is-medium>.ibo-spinner--icon,.ibo-spinner.ibo-is-large>.ibo-spinner--icon{align-self:center;color:#929fb1}.ibo-spinner.ibo-is-small>.ibo-spinner--description,.ibo-spinner.ibo-is-medium>.ibo-spinner--description,.ibo-spinner.ibo-is-large>.ibo-spinner--description{align-self:center;color:#404b5a}.ibo-spinner.ibo-is-small>.ibo-spinner--description{margin-top:4px}.ibo-spinner.ibo-is-medium>.ibo-spinner--description{margin-top:8px}.ibo-spinner.ibo-is-large>.ibo-spinner--description{margin-top:16px}.ibo-title{color:#212934;padding:12px 0}.ibo-title--icon{width:90px;height:90px;min-width:90px;min-height:90px;overflow:hidden}.ibo-title--icon>.ibo-title--icon-level-2{width:80px;height:80px;min-width:80px;min-height:80px}.ibo-title--icon>.ibo-title--icon-level-3{width:70px;height:70px;min-width:70px;min-height:70px}.ibo-title--icon-img,.ibo-title--icon-background{width:100%;height:100%;object-position:center;object-fit:contain;background-size:contain}.ibo-title--icon-img--must-contain,.ibo-title--icon-background--must-contain{object-fit:contain;background-size:contain}.ibo-title--icon-img--must-cover,.ibo-title--icon-background--must-cover{object-fit:cover;background-size:cover}.ibo-title--icon-img--must-zoomout,.ibo-title--icon-background--must-zoomout{width:66.67%;height:66.67%}.ibo-title--subtitle{margin-top:2px;margin-bottom:2px;flex-wrap:wrap}.ibo-title-for-dashlet{padding-top:2em}.ibo-title-for-dashlet--content{background-color:white;border-radius:5px;border:1px solid;border-color:#ccd4db;padding-bottom:1em}.ibo-title-separator{border-radius:5px 5px 0 0;border-color:#3182ce;color:#3182ce;background-color:#3182ce;border:3px solid;margin:0;padding:0}:root{--ibo-datatable-panel--table-spacing: 48px}.ibo-datatable--toolbar{display:flex;justify-content:space-between;align-items:center;padding:0 6px;color:#404b5a}.ibo-datatable--toolbar:first-child{margin-bottom:18px}.ibo-datatable--toolbar:not(:first-child){margin-top:18px}.ibo-datatable--toolbar-left>*:not(:first-child),.ibo-datatable--toolbar-right>*:not(:first-child){margin-left:1rem}.ibo-datatable-header{color:#212934}.ibo-datatable-panel>.ibo-panel--body{padding:32px 0 24px}.ibo-datatable--selection-validation-buttons-toolbar{clear:both;margin-top:10px}.ibo-list-column{max-height:150px;overflow-y:auto}.ibo-sort-order::after{color:#dd6c20}.ibo-sort-order.ibo-is-descending::after{content:""}.ibo-sort-order.ibo-is-ascending::after{content:""}.ibo-sort-order.ibo-is-none::after{content:""}.itop-fieldsorter>.selected{background-color:#bee3f8}.ibo-datatable tbody>tr{transition:background-color 300ms linear}.ibo-datatable tbody>tr:hover,.ibo-datatable tbody>tr.selected:hover{cursor:pointer;background-color:#feebc8}.ibo-datatable tbody>tr.selected{background-color:#fbd38d}.ibo-datatable tbody>tr .ibo-datatable--row-actions-toolbar{justify-content:end}.ibo-datatable tbody>tr>[data-attribute-type="AttributeHTML"],.ibo-datatable tbody>tr>[data-attribute-type="AttributeText"],.ibo-datatable tbody>tr>[data-attribute-type="AttributeLongText"]{max-width:100%;overflow:auto}.ibo-datatable--selected-count,.ibo-datatable--result-count{padding-right:0.2em;padding-left:0.1em}.ibo-datatable[data-status="loading"]{margin-top:18px}.ibo-datatable[data-status="loading"] td,.ibo-datatable[data-status="loading"] th{position:relative;padding:10px 12px}.ibo-datatable[data-status="loading"] tr:nth-child(even){background-color:#f2f2f2}.ibo-datatable[data-status="loading"] th{border-bottom:1px solid #ccd4db}.ibo-datatableconfig--attributes-panel .ibo-multi-column .ibo-column:first-child{margin:8px 0;max-height:150px;overflow-y:scroll}.ibo-datatableconfig--attributes-panel--per-page--input{margin:0 4px;max-width:4em;display:initial}.ibo-datatableconfig--settings-panel .ibo-panel--body{display:flex;flex-direction:row}.ibo-datatableconfig--settings-panel--options-container{flex-grow:1}.ibo-datatableconfig--settings-panel--option{display:flex;flex-direction:row;align-items:first baseline;margin-right:4px}.ibo-prop-header{padding-bottom:14px}.help-text{padding:1px 5px;background-color:#d7e3f8;border:1px solid #c6e7f5;border-radius:5px;margin:5px 0;font-size:0.9em}.form-error ul{padding:1px 5px;background-color:#f8d7da;border:1px solid #f5c6cb;border-radius:5px;margin:5px 0;font-size:0.9em}.subform{background-color:#efefef;border-radius:5px;padding:10px}.form-buttons{margin:20px 0}.form select{padding:0;overflow-y:auto}.form select option{height:30px;display:flex;align-items:center}.turbo-refreshing{opacity:0.5}.ibo-field legend{margin-top:24px}collection-entry-element{margin-top:8px;display:block;padding:10px 10px;background-color:#f5f5f5;border-radius:5px}.ts-control{height:auto;min-height:30px}.ibo-form-actions>.ibo-button>span,.ui-dialog .ibo-form-actions>.ui-button>span,.ibo-form-actions>.ui-datepicker-current>span,.ibo-form-actions>.ui-datepicker-close>span{margin-right:5px}.ibo-form textarea{resize:vertical}.ibo-fieldset~.ibo-fieldset:not(.ibo-column),fieldset~.ibo-fieldset:not(.ibo-column),.ibo-fieldset~fieldset:not(.ibo-column){margin-top:48px}.ibo-multi-column~.ibo-fieldset,.ibo-multi-column~fieldset{margin-top:48px}.ibo-fieldset-legend,.ibo-dashboard-editor--properties-subtitle,.ibo-dashboard--available-dashlet--title,.ibo-dashlet--properties--title,legend{width:100%;margin-bottom:16px;padding-bottom:4px;border-bottom:2px solid #aebecd}.ibo-field{}.ibo-field:not([data-attribute-type="AttributeBlob"], [data-attribute-type="AttributeFile"], [data-attribute-type="AttributeImage"], [data-attribute-type="AttributeCustomFields"], [data-attribute-type="AttributeTagSet"], [data-attribute-type="AttributeEnumSet"], [data-attribute-type="AttributeLinkedSet"], [data-attribute-type="AttributeLinkedSetIndirect"], [data-attribute-type="AttributeClassAttCodeSet"], [data-attribute-type="AttributeQueryAttCodeSet"], .ibo-input-file-select--container){}.ibo-field:not([data-attribute-type="AttributeBlob"], [data-attribute-type="AttributeFile"], [data-attribute-type="AttributeImage"], [data-attribute-type="AttributeCustomFields"], [data-attribute-type="AttributeTagSet"], [data-attribute-type="AttributeEnumSet"], [data-attribute-type="AttributeLinkedSet"], [data-attribute-type="AttributeLinkedSetIndirect"], [data-attribute-type="AttributeClassAttCodeSet"], [data-attribute-type="AttributeQueryAttCodeSet"], .ibo-input-file-select--container) .ibo-field--value{word-break:break-word;white-space:inherit}.ibo-field:not([data-attribute-type="AttributeBlob"], [data-attribute-type="AttributeFile"], [data-attribute-type="AttributeImage"], [data-attribute-type="AttributeCustomFields"], [data-attribute-type="AttributeTagSet"], [data-attribute-type="AttributeEnumSet"], [data-attribute-type="AttributeLinkedSet"], [data-attribute-type="AttributeLinkedSetIndirect"], [data-attribute-type="AttributeClassAttCodeSet"], [data-attribute-type="AttributeQueryAttCodeSet"], .ibo-input-file-select--container) .ibo-field--value *:not(input, select, textarea){word-break:break-word;white-space:inherit}.ibo-field:not([data-attribute-type="AttributeBlob"], [data-attribute-type="AttributeFile"], [data-attribute-type="AttributeImage"], [data-attribute-type="AttributeCustomFields"], [data-attribute-type="AttributeTagSet"], [data-attribute-type="AttributeEnumSet"], [data-attribute-type="AttributeLinkedSet"], [data-attribute-type="AttributeLinkedSetIndirect"], [data-attribute-type="AttributeClassAttCodeSet"], [data-attribute-type="AttributeQueryAttCodeSet"], .ibo-input-file-select--container) .ibo-field--value pre{white-space:break-spaces}.ibo-field[data-attribute-type="AttributeImage"]>.ibo-field--value{display:grid}.ibo-field[data-attribute-type="AttributeImage"]>.ibo-field--value>span{display:inherit}.ibo-field[data-attribute-type="AttributeHTML"][data-attribute-flag-read-only="true"],.ibo-field[data-attribute-type="AttributeText"][data-attribute-flag-read-only="true"],.ibo-field[data-attribute-type="AttributeLongText"][data-attribute-flag-read-only="true"]{display:grid}.ibo-field[data-attribute-type="AttributeHTML"][data-attribute-flag-read-only="true"]>.ibo-field--value,.ibo-field[data-attribute-type="AttributeText"][data-attribute-flag-read-only="true"]>.ibo-field--value,.ibo-field[data-attribute-type="AttributeLongText"][data-attribute-flag-read-only="true"]>.ibo-field--value{max-width:100%;overflow:auto}.ibo-field-large{display:block}.ibo-field-large .ibo-field--label{position:relative;display:flex;align-items:center;max-width:initial;width:100%}.ibo-field-large .ibo-field-small .ibo-field--label{display:table-cell;vertical-align:top;padding-right:10px;min-width:100px;max-width:145px;width:30%}.ibo-field-large .ibo-field--value{margin-top:2px}.ibo-field-large .ibo-field--value>*{--ibo-scrollbar--scrollbar-track-background-color: #f2f2f2}.ibo-field-large.ibo-is-fullscreen{background-color:white}.ibo-field-large.ibo-is-fullscreen .ibo-field--label{position:fixed;width:100%;min-width:initial;max-width:initial;padding:4px 8px;background-color:#f8f9fa;border-bottom:1px solid #ccd4db}.ibo-field-large.ibo-is-fullscreen .ibo-field--value{padding:36px 8px 4px 8px}.ibo-field-large.ibo-is-fullscreen .ibo-field--value>*{height:initial !important;width:initial !important}.ibo-field-small{display:table;width:100%}.ibo-field-small .ibo-field--label{display:table-cell;vertical-align:top;padding-right:10px}.ibo-field--fullscreen-toggler{width:20px;height:20px;border-radius:5px;cursor:pointer}.ibo-field--fullscreen-toggler:hover{background-color:#f2f2f2}.ibo-field--label{min-width:100px;max-width:145px;width:30%;word-break:break-word}.ibo-field--label-small .ibo-field--label{width:20em}.ibo-field--value{width:100%;color:#404b5a}.ibo-field--value .HTML table{table-layout:fixed;width:100%}.ibo-field--label>.ibo-field--comments{flex:auto}.ibo-fieldset-legend>.ibo-field--comments,.ibo-dashboard-editor--properties-subtitle>.ibo-field--comments,.ibo-dashboard--available-dashlet--title>.ibo-field--comments,.ibo-dashlet--properties--title>.ibo-field--comments,legend>.ibo-field--comments{padding-bottom:2px;font-size:1.17rem}.ibo-field--comments{display:table-cell;vertical-align:top;width:5em}.ibo-field--comments>input[type="checkbox"]{margin-left:5px;float:right}.ibo-field--comments>.multi_values,.ibo-field--comments>.mono_value,.ibo-field--comments>.ibo-field--comments--synchro{float:right}.mailto,.tel{white-space:nowrap}.mailto .text_decoration,.tel .text_decoration{margin-right:0.5rem;font-size:0.9em}.object-ref-icon.text_decoration,.object-ref-icon-disabled.text_decoration{margin-right:0.5rem}.ibo-field--enable-bulk,.ibo-field--comments--synchro{display:inline;padding:2px 5px;margin:0 0 0 5px;height:calc(100% - 5px);border-radius:5px;font-weight:bold;white-space:nowrap}.ibo-field--enable-bulk--checkbox{margin-left:8px}.ibo-toolbar{display:flex;align-items:center}.ibo-toolbar.ibo-toolbar--action{position:relative}.ibo-toolbar.ibo-toolbar--button{margin-top:16px}.ibo-toolbar-spacer{flex-grow:1}.ibo-toolbar-vertical-separator{display:inline-flex;border-right:1px solid #aebecd;width:1px;height:16px;margin:0 0.75rem}.search_box{box-sizing:border-box;position:relative;z-index:1100;text-align:center}.search_box *{box-sizing:border-box}.search_form_handler{}.search_form_handler input[type="text"],.search_form_handler select{padding:1px 2px}.search_form_handler:not(.closed) .sf_title .sft_short{display:none}.search_form_handler:not(.closed) .sf_title .sft_toggler{transform:rotateX(180deg);transition:transform 0.5s linear}.search_form_handler.closed{margin-bottom:0.5em;width:150px;overflow:hidden;border-radius:4px}.search_form_handler.closed .sf_criterion_area{height:0;opacity:0;padding:0}.search_form_handler.closed .sf_title{padding:6px 8px;text-align:center;font-size:12px}.search_form_handler.closed .sf_title .sft_long{display:none}.search_form_handler.closed .sf_title .sft_hint,.search_form_handler.closed .sf_title .sfobs_hint{display:none}.search_form_handler:not(.no_auto_submit) .sft_hint{display:none}.search_form_handler:not(.no_auto_submit) .sfc_fg_apply{display:none}.search_form_handler.no_auto_submit .sfc_fg_search{display:none}.search_form_handler.no_auto_submit .sft_hint{display:inline-block}.search_form_handler:not(.hide_obsolete_data) .sfobs_hint{display:none}.search_form_handler.hide_obsolete_data .sfobs_hint{display:inline-block}.search_form_handler.hide_obsolete_data.no_auto_submit .sfobs_hint{margin-left:30px}.search_form_handler .sf_message{display:none;margin:8px 8px 0 8px;border-radius:0px}.search_form_handler .sf_criterion_area{padding:8px 8px 3px 8px}.search_form_handler .sf_criterion_area .sf_criterion_row:not(:first-child){margin-top:20px}.search_form_handler .sf_criterion_area .sf_criterion_row:not(:first-child)::before{content:"";position:absolute;top:-12px;left:0px;width:100%;border-top:1px solid #e1e7ec}.search_form_handler .sf_criterion_area .sf_criterion_row:not(:first-child)::after{content:"or";position:absolute;top:-20px;left:8px;padding-left:5px;padding-right:5px;color:#929fb1;background-color:white}.search_form_handler .sf_criterion_area .sf_criterion_row .sf_criterion_group{display:inline}.search_form_handler .sf_criterion_area .sf_criterion_row .sf_criterion_group .sfc_fg_button,.search_form_handler .sf_criterion_area .sf_criterion_row .sf_criterion_group .sfc_header{border:1px solid #d5dde5;border-radius:3px}.search_form_handler .sf_criterion_area .search_form_criteria,.search_form_handler .sf_criterion_area .sf_more_criterion,.search_form_handler .sf_criterion_area .sf_button{position:relative;display:inline-block;margin-right:10px;margin-top:3px;margin-bottom:3px;vertical-align:top}.search_form_handler .sf_criterion_area .search_form_criteria.opened,.search_form_handler .sf_criterion_area .sf_more_criterion.opened,.search_form_handler .sf_criterion_area .sf_button.opened{margin-bottom:0}.search_form_handler .sf_criterion_area .search_form_criteria.opened .sfc_header,.search_form_handler .sf_criterion_area .search_form_criteria.opened .sfm_header,.search_form_handler .sf_criterion_area .sf_more_criterion.opened .sfc_header,.search_form_handler .sf_criterion_area .sf_more_criterion.opened .sfm_header,.search_form_handler .sf_criterion_area .sf_button.opened .sfc_header,.search_form_handler .sf_criterion_area .sf_button.opened .sfm_header{border-bottom:none !important;padding-bottom:13px}.search_form_handler .sf_criterion_area .search_form_criteria>*,.search_form_handler .sf_criterion_area .sf_more_criterion>*,.search_form_handler .sf_criterion_area .sf_button>*{padding:7px 8px;vertical-align:top;border:solid 1px #d5dde5;border-radius:3px}.search_form_handler .sf_criterion_area .search_form_criteria .sfm_content,.search_form_handler .sf_criterion_area .sf_more_criterion .sfm_content,.search_form_handler .sf_criterion_area .sf_button .sfm_content{position:absolute;z-index:-1;min-width:100%;left:0px;margin-top:-1px}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_fg_buttons,.search_form_handler .sf_criterion_area .search_form_criteria .sfm_buttons,.search_form_handler .sf_criterion_area .sf_more_criterion .sfc_fg_buttons,.search_form_handler .sf_criterion_area .sf_more_criterion .sfm_buttons,.search_form_handler .sf_criterion_area .sf_button .sfc_fg_buttons,.search_form_handler .sf_criterion_area .sf_button .sfm_buttons{white-space:nowrap}.search_form_handler .sf_criterion_area .sf_more_criterion,.search_form_handler .sf_criterion_area .sf_button{min-width:34px;text-align:center}.search_form_handler .sf_criterion_area .search_form_criteria{}.search_form_handler .sf_criterion_area .search_form_criteria.locked{background-color:#d5dde5}.search_form_handler .sf_criterion_area .search_form_criteria.locked .sfc_title{user-select:none;cursor:initial}.search_form_handler .sf_criterion_area .search_form_criteria.draft .sfc_header,.search_form_handler .sf_criterion_area .search_form_criteria.draft .sfc_form_group{border-style:dashed;border-color:#929fb1}.search_form_handler .sf_criterion_area .search_form_criteria.draft .sfc_title{font-style:italic}.search_form_handler .sf_criterion_area .search_form_criteria.opened{z-index:1}.search_form_handler .sf_criterion_area .search_form_criteria.opened .sfc_toggle{transform:rotateX(-180deg)}.search_form_handler .sf_criterion_area .search_form_criteria.opened .sfc_form_group{display:flex;flex-direction:column;margin-top:-1px;z-index:-1}.search_form_handler .sf_criterion_area .search_form_criteria.opened_left .sfc_form_group{left:auto;right:0px}.search_form_handler .sf_criterion_area .search_form_criteria:not(:last-of-type){margin-right:12px}.search_form_handler .sf_criterion_area .search_form_criteria>*{background-color:#f2f2f2;color:#212934}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_toggle,.search_form_handler .sf_criterion_area .search_form_criteria .sfc_close{position:absolute;top:7px;color:#dd6c20}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_locked{position:absolute;top:9px;color:#aebecd}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_toggle{display:inline-block;right:23px;transition:all 0.3s ease-in-out}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_close,.search_form_handler .sf_criterion_area .search_form_criteria .sfc_locked{right:7px}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_title{max-width:240px;padding-right:30px;white-space:nowrap;overflow-x:hidden;text-overflow:ellipsis;cursor:pointer}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_title .sfc_values{font-weight:bold}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group{position:absolute;display:none;max-width:450px;width:max-content;max-height:calc(min(512px, 50vh));overflow-x:auto;overflow-y:hidden}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators{display:flex;flex-direction:column;overflow:auto;min-height:0;font-size:12px}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator.force_hide{display:none !important}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator>label{line-height:20px;white-space:nowrap}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator>label>*{display:inline-block;vertical-align:middle}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_radio{width:12px;margin:0;margin-right:7px}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_name{width:96px}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content input[type="text"]{display:unset;width:160px}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_opc_multichoices{display:flex;flex-direction:column;height:100%}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_opc_multichoices label>input{vertical-align:text-top;margin-left:0;margin-right:8px}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_opc_multichoices .sfc_opc_mc_items_wrapper{overflow-y:auto;margin:0 -8px}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_opc_multichoices .sfc_opc_mc_items_wrapper .sfc_opc_mc_items .sfc_opc_mc_items_list{text-align:left}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_opc_multichoices .sfc_opc_mc_items_wrapper .sfc_opc_mc_items .sfc_opc_mc_items_list.sfc_opc_mc_items_selected{position:relative;padding-top:5px;margin-top:5px}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_opc_multichoices .sfc_opc_mc_items_wrapper .sfc_opc_mc_items .sfc_opc_mc_items_list.sfc_opc_mc_items_selected::before{content:"";position:absolute;border-top:1px solid #d5dde5;width:calc(100% - 12px);margin-left:6px;top:0px}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_opc_multichoices .sfc_opc_mc_items_wrapper .sfc_opc_mc_items .sfc_opc_mc_items_list .sfc_opc_mc_placeholder{padding:15px 8px;font-style:italic;text-align:center}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_opc_multichoices .sfc_opc_mc_items_wrapper .sfc_opc_mc_items .sfc_opc_mc_items_list .sfc_opc_mc_item{padding:4px 8px}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_opc_multichoices .sfc_opc_mc_items_wrapper .sfc_opc_mc_items .sfc_opc_mc_items_list .sfc_opc_mc_item:hover{background-color:#e1e7ec}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_opc_multichoices .sfc_opc_mc_items_wrapper .sfc_opc_mc_items .sfc_opc_mc_items_list .sfc_opc_mc_item label{display:inline-block;width:100%}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_opc_multichoices .sfc_opc_mc_items_wrapper .sfc_opc_mc_items_hint{margin-top:15px;margin-bottom:15px;padding-left:9px;padding-right:9px;color:#6e7a8a;font-size:10px;font-style:italic}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_opc_multichoices .sfc_opc_mc_items_wrapper .sfc_opc_mc_items_hint>span{margin-right:0.5em;font-style:italic}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_search,.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_apply,.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_cancel{margin-top:8px;font-size:1rem}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_search,.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_apply{margin-right:5px}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_more,.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_less{position:absolute;bottom:7px;right:0px;cursor:pointer;color:#2c5382;font-size:10px;font-weight:bold;border:none;background-color:transparent}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_more>span,.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_less>span{margin-left:3px}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operator:not(:first-of-type),.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operator:first-of-type .sfc_op_radio{display:none}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_less{display:none}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_more{display:inline-block}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group.advanced .sfc_fg_operator{margin-bottom:3px}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group.advanced .sfc_fg_operator:last-of-type{margin-bottom:0}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group.advanced .sfc_fg_operator:not(:first-of-type),.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group.advanced .sfc_fg_operator:first-of-type .sfc_op_radio{display:inherit}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group.advanced .sfc_fg_less{display:inline-block}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group.advanced .sfc_fg_more{display:none}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group.advanced .hide_on_advanced{display:none}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group:not(.advanced) .hide_on_less{display:none}.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_raw>*{border-color:transparent}.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_raw .sfc_title{cursor:initial;padding-right:20px}.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_raw .sfc_form_group{display:none}.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_enum .sfc_form_group .sfc_fg_operator_in{display:flex;flex-direction:column;height:100%;min-height:0}.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_enum .sfc_form_group .sfc_fg_operator_in>label{display:flex;height:100%;min-height:0;width:100%;line-height:initial;white-space:nowrap}.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_enum .sfc_form_group .sfc_fg_operator_in>label .sfc_op_content{width:100%}.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_tag_set .sfc_form_group .sfc_fg_operator_in>label{display:inline-block;width:100%;line-height:initial;white-space:nowrap}.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_tag_set .sfc_form_group .sfc_fg_operator_in>label .sfc_op_content{width:100%}.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_numeric .sfc_fg_operators .sfc_fg_operator.sfc_fg_operator_between .sfc_op_content_from_outer{display:inline}.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_numeric .sfc_fg_operators .sfc_fg_operator.sfc_fg_operator_between .sfc_op_content_until_outer{display:inline;margin-left:5px}.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_numeric .sfc_fg_operators .sfc_fg_operator.sfc_fg_operator_between label.sfc_op_content_from_label,.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_numeric .sfc_fg_operators .sfc_fg_operator.sfc_fg_operator_between label.sfc_op_content_until_label{width:45px;display:inline-block}.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_numeric .sfc_fg_operators .sfc_fg_operator.sfc_fg_operator_between input[type="text"]{width:77px}.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_date_time .sfc_form_group.advanced .sfc_fg_operator_between,.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_date .sfc_form_group.advanced .sfc_fg_operator_between{margin-bottom:5px}.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_date_time .sfc_fg_operator_between_days input,.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_date .sfc_fg_operator_between_days input{width:135px}.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_date_time button.ui-datepicker-trigger,.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_date button.ui-datepicker-trigger{background:none;border:none;height:100%;padding:2px}.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_date_time button.ui-datepicker-trigger img,.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_date button.ui-datepicker-trigger img{vertical-align:middle}.search_form_handler .sf_criterion_area .sf_more_criterion.opened{z-index:2}.search_form_handler .sf_criterion_area .sf_more_criterion.opened .sfm_content{display:inherit}.search_form_handler .sf_criterion_area .sf_more_criterion.opened_left .sfm_content{left:auto;right:0px}.search_form_handler .sf_criterion_area .sf_more_criterion>*{background-color:white;color:#37474f}.search_form_handler .sf_criterion_area .sf_more_criterion .sfm_toggler .sfm_tg_title{margin-right:7px}.search_form_handler .sf_criterion_area .sf_more_criterion .sfm_toggler .sfm_tg_icon{color:#dd6c20}.search_form_handler .sf_criterion_area .sf_more_criterion .sfm_content{display:none;min-width:200px}.search_form_handler .sf_criterion_area .sf_more_criterion .sfm_content .sfm_lists{margin:0 -8px;padding:0 8px;max-height:400px;overflow-x:hidden;overflow-y:auto}.search_form_handler .sf_criterion_area .sf_more_criterion .sfm_content .sfm_lists .sfl_items>li:hover{background-color:#e1e7ec}.search_form_handler .sf_criterion_area .sf_more_criterion .sfm_content .sfm_buttons{display:none}.search_form_handler .sf_criterion_area .sf_more_criterion .sfm_content .sfm_buttons button{margin-top:8px;margin-right:5px;padding:3px 6px;font-size:11px}.search_form_handler .sf_criterion_area .sf_more_criterion .sfm_content .sfm_buttons button:last-of-type{margin-right:0}.search_form_handler .sf_criterion_area .sf_button{cursor:pointer}.search_form_handler .sf_criterion_area .sf_button>*{background-color:white;color:#dd6c20}.search_form_handler .sf_list:not(:first-of-type) .sfl_title{border-top:1px solid #ccd4db;padding-top:8px;margin-top:5px}.search_form_handler .sf_list .sfl_title{font-weight:bold}.search_form_handler .sf_list .sfl_items{margin:5px -8px 0 -8px;padding:0;text-align:left}.search_form_handler .sf_list .sfl_items>li{padding:4px 8px;list-style:none;white-space:nowrap}.search_form_handler .sf_list .sfl_items>li:hover{background-color:#e1e7ec}.search_form_handler .sf_list .sfl_items>li.sfl_i_placeholder{font-style:italic;opacity:0.8}.search_form_handler .sf_list .sfl_items>li>label{display:inline-block;width:100%}.search_form_handler .sf_list .sfl_items>li>label>*{vertical-align:middle}.search_form_handler .sf_list .sfl_items>li>label>input[type="checkbox"]{margin-left:0;margin-right:8px}.search_form_handler .sf_filter{position:relative;margin-top:8px;margin-bottom:8px}.search_form_handler .sf_filter input,.search_form_handler .sf_filter button,.search_form_handler .sf_filter .sff_picto{vertical-align:middle;height:22px}.search_form_handler .sf_filter input,.search_form_handler .sf_filter button{border:1px solid #ABABAB}.search_form_handler .sf_filter input{width:100% !important}.search_form_handler .sf_filter button{width:23px;background-color:white;color:#dd6c20;font-size:10px}.search_form_handler .sf_filter button:first-of-type{margin-left:5px}.search_form_handler .sf_filter button:not(:first-of-type){border-left:transparent}.search_form_handler .sf_filter .sff_input_wrapper{position:relative}.search_form_handler .sf_filter .sff_input_wrapper input[type="text"]{display:unset}.search_form_handler .sf_filter .sff_input_wrapper .sff_picto{position:absolute;right:7px;top:3px;user-select:none;color:#404b5a}.search_form_handler .sf_filter .sff_input_wrapper .sff_reset{display:none}.search_form_handler .sf_filter .sff_input_wrapper input::-ms-clear{display:none}.search_form_handler .sf_filter.sf_with_buttons input{width:calc(100% - 28px) !important;min-width:120px}.sft_hint,.sfobs_hint,.sft_toggler{margin-left:8px;color:#404b5a}.sf_results_placeholder{margin-top:24px;text-align:center}.sf_results_placeholder button{margin-top:8px}.sf_results_placeholder button>span{margin-right:0.5em}.ibo-search-form-panel{z-index:3;margin-bottom:8px}.ibo-search-form-panel .ibo-panel--body{padding:18px 14px 10px;overflow:initial}.ibo-search-form-panel .ibo-panel--body::before{border-radius:5px 5px 0 0}#ibo-main-content .search_form_handler .sf_criterion_area{padding:0}.sfm_tg_title{display:none}.ibo-criterion-group:empty~.sf_more_criterion .sfm_tg_title{display:unset}.sf_results_area{z-index:1;margin-bottom:300px}.ibo-search-form-panel .ibo-panel--body.ibo-is-sticking{position:fixed;border-radius:0;border-bottom-color:transparent}.ibo-datatable-panel.ibo-is-sticking .ibo-panel--header,.ibo-datatable-panel.ibo-is-sticking .ibo-object-summary--header{z-index:0}.ibo-datatable-panel.ibo-is-sticking .ibo-datatable--toolbar{position:fixed;z-index:2;padding-bottom:4px;background-color:white;border-left:1px solid #ccd4db;border-right:1px solid #ccd4db}.ibo-datatable-panel.ibo-is-sticking .dataTables_scrollHead{position:fixed !important;z-index:2;background-color:white;border-left:1px solid #ccd4db !important;border-right:1px solid #ccd4db !important}.ibo-field-badge{display:inline-flex;align-items:baseline;margin:0;padding:4px 10px;border-radius:3px;background-color:var(--ibo-main-color);color:var(--ibo-complementary-color)}.ibo-field-badge--decoration+.ibo-field-badge--label{margin-left:0.5rem}.ibo-input-file-select--container .ibo-input-file-select .ibo-input-file-select--file-input{display:none}.ibo-input-file-select--container .ibo-input-file-select .ibo-input-file-select--file-name{margin-left:10px}.ibo-medallion-icon{display:flex;padding:13px 0}.ibo-medallion-icon--image{height:48px;width:48px;padding:2px;border-radius:100%;background-color:#bee3f8}.ibo-medallion-icon--description{display:inline-block;padding-left:8px}@keyframes decreaseHighlight{0%{height:100%}8%{border-radius:0 0 0 3px}100%{height:0}}.ibo-toast{display:inline-flex;position:fixed;align-items:center;max-width:calc(50% - 20px);padding:12px 8px 12px 16px;border-radius:3px;box-shadow:0 2px 4px rgba(0, 0, 0, 0.12), 0 3px 6px rgba(0, 0, 0, 0.15);transition:all 0.4s cubic-bezier(0.215, 0.61, 0.355, 1);z-index:2147483647}.ibo-toast::before{display:block;position:absolute;top:0;left:0;content:"";width:4px;height:100%;top:initial;bottom:0;border-radius:3px 0 0 3px}.ibo-toast.ibo-is-auto-closeable::before{animation:decreaseHighlight 5s linear forwards}.ibo-toast:hover::before{animation:none}:root{}.ibo-navigation-menu{position:relative;height:100vh}.ibo-navigation-menu.ibo-is-expanded .ibo-navigation-menu--square-company-logo{display:none}.ibo-navigation-menu.ibo-is-expanded .ibo-navigation-menu--full-company-logo{display:flex}.ibo-navigation-menu.ibo-is-expanded .ibo-navigation-menu--silo-selection{display:inline-block}.ibo-navigation-menu.ibo-is-expanded .ibo-navigation-menu--silo-visual-hint{display:none}.ibo-navigation-menu.ibo-is-expanded .ibo-navigation-menu--body{width:310px}.ibo-navigation-menu.ibo-is-expanded .ibo-navigation-menu--body .ibo-navigation-menu--toggler-bar:nth-child(1){top:4px;left:7px;width:14px;transform:rotateZ(-45deg)}.ibo-navigation-menu.ibo-is-expanded .ibo-navigation-menu--body .ibo-navigation-menu--toggler-bar:nth-child(2){top:8px;left:7px;width:0;opacity:0}.ibo-navigation-menu.ibo-is-expanded .ibo-navigation-menu--body .ibo-navigation-menu--toggler-bar:nth-child(3){top:12px;left:7px;width:14px;transform:rotateZ(45deg)}.ibo-navigation-menu.ibo-is-expanded .ibo-navigation-menu--body .ibo-navigation-menu--menu-group:not(.ibo-is-active):active{border-radius:16px}.ibo-navigation-menu.ibo-is-expanded .ibo-navigation-menu--body .ibo-navigation-menu--bottom-part{padding:24px 0 12px}.ibo-navigation-menu.ibo-is-expanded .ibo-navigation-menu--body .ibo-navigation-menu--bottom-part .ibo-navigation-menu--notifications .ibo-navigation-menu--notifications-toggler{display:none}.ibo-navigation-menu.ibo-is-expanded .ibo-navigation-menu--body .ibo-navigation-menu--bottom-part .ibo-navigation-menu--user-info{height:100%}.ibo-navigation-menu.ibo-is-expanded .ibo-navigation-menu--body .ibo-navigation-menu--bottom-part .ibo-navigation-menu--user-info .ibo-navigation-menu--user-welcome-message,.ibo-navigation-menu.ibo-is-expanded .ibo-navigation-menu--body .ibo-navigation-menu--bottom-part .ibo-navigation-menu--user-info .ibo-navigation-menu--user-notifications,.ibo-navigation-menu.ibo-is-expanded .ibo-navigation-menu--body .ibo-navigation-menu--bottom-part .ibo-navigation-menu--user-info .ibo-navigation-menu--user-organization{display:block}.ibo-navigation-menu.ibo-is-expanded .ibo-navigation-menu--body .ibo-navigation-menu--bottom-part .ibo-navigation-menu--user-info .ibo-navigation-menu--user-picture{margin-top:-60px;width:72px;height:72px;border:solid 3px #263238}.ibo-navigation-menu.ibo-is-expanded .ibo-navigation-menu--body .ibo-navigation-menu--bottom-part .ibo-navigation-menu--user-info .ibo-navigation-menu--user-picture .ibo-navigation-menu--user-picture--image{max-width:72px;max-height:72px}.ibo-navigation-menu.ibo-is-active .ibo-navigation-menu--drawer{right:calc(-1 * 312px)}.ibo-navigation-menu.ibo-is-filtered .ibo-navigation-menu--menu-filter-clear{display:block}.ibo-navigation-menu.ibo-is-filtered .ibo-navigation-menu--menu-nodes{margin-bottom:48px}.ibo-navigation-menu.ibo-is-filtered .ibo-navigation-menu--menu-nodes .ibo-navigation-menu--menu-nodes-title{margin-bottom:8px}.ibo-navigation-menu--body,.ibo-navigation-menu--drawer{height:100vh}.ibo-navigation-menu--body{z-index:1;display:flex;flex-direction:column;justify-content:space-between;align-items:stretch;height:100vh;width:60px;background-color:#263238;transition:width 0.1s ease-in-out}.ibo-navigation-menu--top-part{z-index:2;min-height:120px;padding:12px 16px;overflow:hidden}.ibo-navigation-menu--middle-part{z-index:1;flex-grow:1;overflow-y:auto;padding:24px 16px 16px;scrollbar-width:thin;scrollbar-color:#d5dde5 rgba(255, 255, 255, 0)}.ibo-navigation-menu--middle-part::-webkit-scrollbar{width:5px}.ibo-navigation-menu--middle-part::-webkit-scrollbar-track{background-color:rgba(255, 255, 255, 0)}.ibo-navigation-menu--middle-part::-webkit-scrollbar-thumb{background-color:#d5dde5}.ibo-navigation-menu--bottom-part{z-index:2;padding-top:20px;padding-bottom:16px;height:126px;background-color:#404b5a;justify-content:space-between;flex-direction:column}.ibo-navigation-menu--toggler,.ibo-navigation-menu--menu-group{margin:calc(-1 * 10px) calc(-1 * 8px);padding:10px 8px;border-radius:5px}.ibo-navigation-menu--square-company-logo{display:flex;width:38px;height:38px;margin:0 -5px 44px}.ibo-navigation-menu--square-company-logo>img{object-fit:contain}.ibo-navigation-menu--full-company-logo{display:none;width:310px;height:70px;margin:0 0 12px -16px}.ibo-navigation-menu--full-company-logo>img{object-fit:contain;margin:0 auto}.ibo-navigation-menu--toggler{position:relative;display:inline-flex;width:44px}.ibo-navigation-menu--toggler:hover,.ibo-navigation-menu--toggler:active{background-color:#455a64}.ibo-navigation-menu--toggler:hover .ibo-navigation-menu--toggler-bar,.ibo-navigation-menu--toggler:active .ibo-navigation-menu--toggler-bar{background-color:white}.ibo-navigation-menu--toggler-icon{position:relative;display:flex;height:20px;width:28px}.ibo-navigation-menu--toggler-bar{position:absolute;display:block;height:3px;width:100%;opacity:1;transition:all 0.2s linear;background-color:#d5dde5}.ibo-navigation-menu--toggler-bar:nth-child(1){top:0}.ibo-navigation-menu--toggler-bar:nth-child(2){top:8px}.ibo-navigation-menu--toggler-bar:nth-child(3){top:16px}.ibo-navigation-menu--silo-selection{position:absolute;display:none;width:70%;margin-left:15px}.ibo-navigation-menu--silo-selection .ibo-input-wrapper .ibo-input,.ibo-navigation-menu--silo-selection .ui_tpicker_hour_slider .ibo-input,.ibo-navigation-menu--silo-selection .ui_tpicker_hour_slider .ui-autocomplete-input,.ibo-navigation-menu--silo-selection .ui_tpicker_hour_slider .ui-multiselect,.ibo-navigation-menu--silo-selection .ui_tpicker_hour_slider .dataTables_length select,.dataTables_length .ibo-navigation-menu--silo-selection .ui_tpicker_hour_slider select,.ibo-navigation-menu--silo-selection .ui_tpicker_hour_slider .ui_tpicker_hour_slider>select,.ibo-navigation-menu--silo-selection .ui_tpicker_hour_slider .ui_tpicker_minute_slider>select,.ibo-navigation-menu--silo-selection .ui_tpicker_hour_slider .ui_tpicker_second_slider>select,.ibo-navigation-menu--silo-selection .ui_tpicker_hour_slider select.ibo-input-select-placeholder,.ibo-navigation-menu--silo-selection .ui_tpicker_hour_slider .ibo-datatableconfig--attributes-panel--per-page--input,.ibo-navigation-menu--silo-selection .ui_tpicker_hour_slider .search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content input[type="text"],.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content .ibo-navigation-menu--silo-selection .ui_tpicker_hour_slider input[type="text"],.ibo-navigation-menu--silo-selection .ui_tpicker_hour_slider .search_form_handler .sf_filter .sff_input_wrapper input[type="text"],.search_form_handler .sf_filter .sff_input_wrapper .ibo-navigation-menu--silo-selection .ui_tpicker_hour_slider input[type="text"],.ibo-navigation-menu--silo-selection .ui_tpicker_minute_slider .ibo-input,.ibo-navigation-menu--silo-selection .ui_tpicker_minute_slider .ui-autocomplete-input,.ibo-navigation-menu--silo-selection .ui_tpicker_minute_slider .ui-multiselect,.ibo-navigation-menu--silo-selection .ui_tpicker_minute_slider .dataTables_length select,.dataTables_length .ibo-navigation-menu--silo-selection .ui_tpicker_minute_slider select,.ibo-navigation-menu--silo-selection .ui_tpicker_minute_slider .ui_tpicker_hour_slider>select,.ibo-navigation-menu--silo-selection .ui_tpicker_minute_slider .ui_tpicker_minute_slider>select,.ibo-navigation-menu--silo-selection .ui_tpicker_minute_slider .ui_tpicker_second_slider>select,.ibo-navigation-menu--silo-selection .ui_tpicker_minute_slider select.ibo-input-select-placeholder,.ibo-navigation-menu--silo-selection .ui_tpicker_minute_slider .ibo-datatableconfig--attributes-panel--per-page--input,.ibo-navigation-menu--silo-selection .ui_tpicker_minute_slider .search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content input[type="text"],.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content .ibo-navigation-menu--silo-selection .ui_tpicker_minute_slider input[type="text"],.ibo-navigation-menu--silo-selection .ui_tpicker_minute_slider .search_form_handler .sf_filter .sff_input_wrapper input[type="text"],.search_form_handler .sf_filter .sff_input_wrapper .ibo-navigation-menu--silo-selection .ui_tpicker_minute_slider input[type="text"],.ibo-navigation-menu--silo-selection .ui_tpicker_second_slider .ibo-input,.ibo-navigation-menu--silo-selection .ui_tpicker_second_slider .ui-autocomplete-input,.ibo-navigation-menu--silo-selection .ui_tpicker_second_slider .ui-multiselect,.ibo-navigation-menu--silo-selection .ui_tpicker_second_slider .dataTables_length select,.dataTables_length .ibo-navigation-menu--silo-selection .ui_tpicker_second_slider select,.ibo-navigation-menu--silo-selection .ui_tpicker_second_slider .ui_tpicker_hour_slider>select,.ibo-navigation-menu--silo-selection .ui_tpicker_second_slider .ui_tpicker_minute_slider>select,.ibo-navigation-menu--silo-selection .ui_tpicker_second_slider .ui_tpicker_second_slider>select,.ibo-navigation-menu--silo-selection .ui_tpicker_second_slider select.ibo-input-select-placeholder,.ibo-navigation-menu--silo-selection .ui_tpicker_second_slider .ibo-datatableconfig--attributes-panel--per-page--input,.ibo-navigation-menu--silo-selection .ui_tpicker_second_slider .search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content input[type="text"],.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content .ibo-navigation-menu--silo-selection .ui_tpicker_second_slider input[type="text"],.ibo-navigation-menu--silo-selection .ui_tpicker_second_slider .search_form_handler .sf_filter .sff_input_wrapper input[type="text"],.search_form_handler .sf_filter .sff_input_wrapper .ibo-navigation-menu--silo-selection .ui_tpicker_second_slider input[type="text"],.ibo-navigation-menu--silo-selection .ibo-input-wrapper .ui-autocomplete-input,.ibo-navigation-menu--silo-selection .ibo-input-wrapper .ui-multiselect,.ibo-navigation-menu--silo-selection .ibo-input-wrapper .dataTables_length select,.dataTables_length .ibo-navigation-menu--silo-selection .ibo-input-wrapper select,.ibo-navigation-menu--silo-selection .ibo-input-wrapper .ui_tpicker_hour_slider>select,.ibo-navigation-menu--silo-selection .ibo-input-wrapper .ui_tpicker_minute_slider>select,.ibo-navigation-menu--silo-selection .ibo-input-wrapper .ui_tpicker_second_slider>select,.ibo-navigation-menu--silo-selection .ibo-input-wrapper select.ibo-input-select-placeholder,.ibo-navigation-menu--silo-selection .ibo-input-wrapper .ibo-datatableconfig--attributes-panel--per-page--input,.ibo-navigation-menu--silo-selection .ibo-input-wrapper .search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content input[type="text"],.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content .ibo-navigation-menu--silo-selection .ibo-input-wrapper input[type="text"],.ibo-navigation-menu--silo-selection .ibo-input-wrapper .search_form_handler .sf_filter .sff_input_wrapper input[type="text"],.search_form_handler .sf_filter .sff_input_wrapper .ibo-navigation-menu--silo-selection .ibo-input-wrapper input[type="text"]{padding-right:38px;overflow:hidden}.ibo-navigation-menu--silo-selection .ibo-input-wrapper .ibo-input-select-autocomplete,.ibo-navigation-menu--silo-selection .ui_tpicker_hour_slider .ibo-input-select-autocomplete,.ibo-navigation-menu--silo-selection .ui_tpicker_minute_slider .ibo-input-select-autocomplete,.ibo-navigation-menu--silo-selection .ui_tpicker_second_slider .ibo-input-select-autocomplete{padding-right:60px}.ibo-navigation-menu--silo-selection .ibo-input-wrapper .ibo-input-select-autocomplete~.ibo-input-select--action-button--search,.ibo-navigation-menu--silo-selection .ui_tpicker_hour_slider .ibo-input-select-autocomplete~.ibo-input-select--action-button--search,.ibo-navigation-menu--silo-selection .ui_tpicker_minute_slider .ibo-input-select-autocomplete~.ibo-input-select--action-button--search,.ibo-navigation-menu--silo-selection .ui_tpicker_second_slider .ibo-input-select-autocomplete~.ibo-input-select--action-button--search{margin-left:-42px}.ibo-navigation-menu--silo-selection .ibo-input-wrapper .ibo-input-select-autocomplete~.ibo-input-select--action-button--clear,.ibo-navigation-menu--silo-selection .ui_tpicker_hour_slider .ibo-input-select-autocomplete~.ibo-input-select--action-button--clear,.ibo-navigation-menu--silo-selection .ui_tpicker_minute_slider .ibo-input-select-autocomplete~.ibo-input-select--action-button--clear,.ibo-navigation-menu--silo-selection .ui_tpicker_second_slider .ibo-input-select-autocomplete~.ibo-input-select--action-button--clear{margin-left:-72px}.ibo-navigation-menu--silo-selection .ibo-input-wrapper .ibo-input-select-autocomplete~.ibo-input-select--action-button--hierarchy,.ibo-navigation-menu--silo-selection .ui_tpicker_hour_slider .ibo-input-select-autocomplete~.ibo-input-select--action-button--hierarchy,.ibo-navigation-menu--silo-selection .ui_tpicker_minute_slider .ibo-input-select-autocomplete~.ibo-input-select--action-button--hierarchy,.ibo-navigation-menu--silo-selection .ui_tpicker_second_slider .ibo-input-select-autocomplete~.ibo-input-select--action-button--hierarchy{margin-left:-60px}.ibo-navigation-menu--silo-visual-hint{position:absolute;top:2px;right:0;width:16px;height:16px;background-color:#e53e3e;border:2px solid #263238;border-radius:100%}.ibo-navigation-menu--menu-group{display:flex;justify-content:left;align-items:center;white-space:nowrap;overflow-x:hidden;color:#d5dde5;transition-property:background-color, color, padding, margin, border-radius;transition-duration:0.1s;transition-timing-function:linear}.ibo-navigation-menu--menu-group>.ibo-navigation-menu--menu-group-icon{display:flex}.ibo-navigation-menu--menu-group .ibo-navigation-menu--menu-group-title{flex-grow:1}.ibo-navigation-menu--menu-group:not(:last-child){margin-bottom:20px}.ibo-navigation-menu--menu-group:not(.ibo-is-active):hover,.ibo-navigation-menu--menu-group:not(.ibo-is-active):active{color:white;background-color:#455a64}.ibo-navigation-menu--menu-group:not(.ibo-is-active):active{border-radius:100%}.ibo-navigation-menu--menu-group.ibo-is-active{margin-right:calc(-2 * 8px);padding-right:calc(2 - 8px);color:#37474f;background-color:#f8f9fa;border-radius:5px 0 0 5px}.ibo-navigation-menu--menu-group.ibo-is-active .ibo-navigation-menu--menu-group-icon{color:#ea7d1e}.ibo-navigation-menu--menu-group-icon{width:28px;min-width:28px;justify-content:center;font-size:1.83rem}.ibo-navigation-menu--menu-group-icon::before{width:28px}.ibo-navigation-menu--menu-group-title{margin-left:16px;justify-content:left}.ibo-navigation-menu--drawer{position:absolute;z-index:-1;top:0;bottom:0;right:0;display:flex;flex-direction:column;justify-content:flex-start;width:312px;padding:32px 20px;background-color:#f8f9fa;border-right:1px solid #d5dde5;transition:right 0.2s ease-in-out}.ibo-navigation-menu--menu-filter{position:relative}.ibo-navigation-menu--menu-filter-input{width:100%;padding:8px 10px;color:#212934;background-color:white;border:1px solid #d5dde5;border-radius:3px;padding-right:76px}.ibo-navigation-menu--menu-filter-input::placeholder{color:#6e7a8a}.ibo-navigation-menu--menu-filter-input:-ms-input-placeholder,.ibo-navigation-menu--menu-filter-input::-ms-input-placeholder{color:#6e7a8a}.ibo-navigation-menu--menu-filter-clear{display:none;position:absolute;top:8px;right:60px;padding:3px 3px}.ibo-navigation-menu--menu-filter-hotkey{position:absolute;top:6.5px;right:10px;border:1px solid #ccd4db;border-radius:3px;color:#6e7a8a;padding:2px 4px}.ibo-navigation-menu--menu-filter-hint{position:relative;margin-top:16px;padding-right:12px;color:#6e7a8a}.ibo-navigation-menu--menu-filter-hint-close{position:absolute;top:1px;right:2px}.ibo-navigation-menu--menu--placeholder{width:100%;margin-top:50px}.ibo-navigation-menu--menu--placeholder-image>svg{display:block;width:90%;height:auto;margin:auto}.ibo-navigation-menu--menu--placeholder-hint{margin-top:8px;text-align:center}.ibo-navigation-menu--menu-groups{overflow-y:auto;overflow-x:hidden;margin:50px calc(-1 * 20px) 0 calc(-1 * 20px);padding-left:20px;padding-right:20px;width:inherit}.ibo-navigation-menu--menu-nodes{display:none}.ibo-navigation-menu--menu-nodes ul li>a,.ibo-navigation-menu--menu-nodes ul li>span{margin:0 -10px;padding:6px 10px;border-radius:0;color:#6e7a8a}.ibo-navigation-menu--menu-nodes ul li>a{color:inherit}.ibo-navigation-menu--menu-nodes ul li>a:hover{background-color:#e1e7ec;border-radius:5px}.ibo-navigation-menu--menu-nodes ul ul{padding-left:20px}.ibo-navigation-menu--menu-nodes.ibo-is-active{display:block}.ibo-navigation-menu--menu-nodes-title{margin-top:0;margin-bottom:32px;word-break:break-word}.ibo-navigation-menu--menu-node-title{display:flex;justify-content:space-between;align-items:center}.ibo-navigation-menu--menu-node-counter{margin-left:8px;padding:2px 6px;width:34px;min-width:34px;text-align:center;background:#e1e7ec;border-radius:5px}.ibo-navigation-menu--notifications{position:relative;display:flex;flex-direction:column;align-content:center}.ibo-navigation-menu--notifications-toggler{position:relative;font-size:2rem;color:#929fb1}.ibo-navigation-menu--notifications-toggler:hover,.ibo-navigation-menu--notifications-toggler.ibo-is-loaded:hover{color:#f2f2f2}.ibo-navigation-menu--notifications-toggler.ibo-is-loaded{color:#d5dde5}.ibo-navigation-menu--notifications-toggler.ibo-is-loaded:not(.ibo-is-empty) .ibo-navigation-menu--notifications-toggler--new-messages{display:inline}.ibo-navigation-menu--notifications-toggler .ibo-navigation-menu--notifications-toggler--new-messages{top:-2px;right:-7px;width:16px;height:16px}.ibo-navigation-menu--user-notifications--toggler{position:relative}.ibo-navigation-menu--user-notifications--toggler.ibo-is-loaded{color:#d5dde5}.ibo-navigation-menu--user-notifications--toggler.ibo-is-loaded:not(.ibo-is-empty) .ibo-navigation-menu--notifications-toggler--new-messages{display:inline}.ibo-navigation-menu--user-notifications--toggler .ibo-navigation-menu--notifications-toggler--new-messages{top:-2px;right:-5px;width:10px;height:10px}.ibo-navigation-menu--notifications-toggler--new-messages{position:absolute;display:none;background-color:#e53e3e;border:2px solid #404b5a;border-radius:100%}.ibo-navigation-menu--user-info{justify-content:space-between;flex-direction:column}.ibo-navigation-menu--user-info .ibo-navigation-menu--user-picture{width:36px;height:36px;overflow:hidden;background-color:#d5dde5;border-radius:100%}.ibo-navigation-menu--user-info .ibo-navigation-menu--user-picture .ibo-navigation-menu--user-picture--image{display:flex;max-width:36px;max-height:36px}.ibo-navigation-menu--user-info .ibo-navigation-menu--user-welcome-message,.ibo-navigation-menu--user-info .ibo-navigation-menu--user-organization,.ibo-navigation-menu--user-info .ibo-navigation-menu--user-notifications{display:none;text-align:center;color:white}.ibo-navigation-menu--user-info .ibo-navigation-menu--user-welcome-message .ibo-navigation-menu--user-welcome-message--text,.ibo-navigation-menu--user-info .ibo-navigation-menu--user-welcome-message .ibo-navigation-menu--user-welcome-message--toggler{color:white}.ibo-navigation-menu--user-info .ibo-navigation-menu--user-welcome-message--toggler{padding-left:6px}.ibo-navigation-menu--user-info .ibo-navigation-menu--user-notifications .ibo-navigation-menu--user-notifications--text{color:white}.ibo-navigation-menu--user-info .ibo-navigation-menu--user-notifications .ibo-navigation-menu--user-notifications--toggler--icon{padding-left:5px}.ibo-navigation-menu--user-info .ibo-navigation-menu--user-organization{color:#ebf8ff}.ibo-navigation-menu--user-info .ibo-navigation-menu--user-menu-container{position:absolute;bottom:10px}.ibo-navigation-menu--user-info .ibo-navigation-menu--user-menu-container .ibo-popover-menu>.ibo-popover-menu--section:nth-child(odd),.ibo-navigation-menu--user-info .ibo-navigation-menu--user-menu-container .ui-menu>.ibo-popover-menu--section:nth-child(odd),.ibo-navigation-menu--user-info .ibo-navigation-menu--user-menu-container .ui-menu>.ui-multiselect-checkboxes:nth-child(odd),.ibo-navigation-menu--user-info .ibo-navigation-menu--user-menu-container .ui-multiselect-menu>.ibo-popover-menu--section:nth-child(odd),.ibo-navigation-menu--user-info .ibo-navigation-menu--user-menu-container .ui-multiselect-menu>.ui-multiselect-checkboxes:nth-child(odd),.ibo-navigation-menu--user-info .ibo-navigation-menu--user-menu-container .ibo-input-select-icon--menu>.ibo-popover-menu--section:nth-child(odd),.ibo-navigation-menu--user-info .ibo-navigation-menu--user-menu-container .ibo-input-select-icon--menu>.ui-multiselect-checkboxes:nth-child(odd),.ibo-navigation-menu--user-info .ibo-navigation-menu--user-menu-container .graph_config .toolkit_menu.graph>ul>li ul>.ibo-popover-menu--section:nth-child(odd),.ibo-navigation-menu--user-info .ibo-navigation-menu--user-menu-container .graph_config .toolkit_menu.graph>ul>li ul>.ui-multiselect-checkboxes:nth-child(odd),.graph_config .toolkit_menu.graph>ul>li .ibo-navigation-menu--user-info .ibo-navigation-menu--user-menu-container ul>.ibo-popover-menu--section:nth-child(odd),.ibo-navigation-menu--user-info .ibo-navigation-menu--user-menu-container .ibo-popover-menu>.ui-multiselect-checkboxes:nth-child(odd){background-color:#f8f9fa}:root{--ibo-top-bar--height: 54px;--ibo-top-bar--padding-left: 16px;--ibo-top-bar--padding-right: 16px;--ibo-top-bar--padding-y: 0;--ibo-top-bar--background-color: white;--ibo-top-bar--elements-spacing: 32px;--ibo-top-bar--quick-actions--margin-right: 32px}.ibo-top-bar{height:var(--ibo-top-bar--height);padding:var(--ibo-top-bar--padding-y) var(--ibo-top-bar--padding-right) var(--ibo-top-bar--padding-y) var(--ibo-top-bar--padding-left);background-color:var(--ibo-top-bar--background-color)}.ibo-top-bar .ibo-breadcrumbs{flex-grow:1;overflow-x:hidden}.ibo-top-bar--quick-actions{margin-right:var(--ibo-top-bar--quick-actions--margin-right)}.ibo-top-bar--toolbar-dashboard-title{max-width:350px}.ibo-top-bar--toolbar-dashboard-menu-toggler{display:flex;align-items:center}#ibo-center-container.ibo-center-container--with-side-content{display:flex;align-items:stretch}#ibo-center-container.ibo-center-container--with-side-content #ibo-main-content{flex-grow:1}.ibo-v-spacer{padding-top:1em}#ibo-side-content{background-color:white;border-left:1px solid #ccd4db}.ibo-details{margin-top:5px}.ibo-tab-container:not(.ibo-is-scrollable):not([data-status="loaded"]) .ibo-tab-container--tab-container:not(:first-child){display:none}.ibo-tab-container--tabs-list{position:relative;height:36px;background-color:#f8f9fa}.ibo-tab-container--tab-header,.ibo-tab-container--extra-tabs-container{color:#404b5a}.ibo-tab-container--tab-header:hover:not(.ui-state-disabled),.ibo-tab-container--extra-tabs-container:hover:not(.ui-state-disabled){color:#2c5382;background-color:#e1e7ec}.ibo-tab-container--tab-header.ui-tabs-active,.ui-tabs-active.ibo-tab-container--extra-tabs-container{color:#2c5382}.ibo-tab-container--tab-toggler,.ibo-tab-container--extra-tabs-list-toggler{padding-left:24px;padding-right:24px}.ibo-tab-container--extra-tabs-container{position:absolute;top:0;bottom:0;right:0;background-color:#f8f9fa}.ibo-tab-container--extra-tabs-list-toggler{padding-left:12px;padding-right:12px}.ibo-tab-container--extra-tabs-list{position:fixed;z-index:10;max-height:300px;display:flex;flex-direction:column;overflow-y:auto;background-color:#f8f9fa;border-radius:3px}.ibo-tab-container--extra-tab-toggler{padding:8px 16px;max-width:220px;color:#6e7a8a;overflow-x:clip}.ibo-tab-container--extra-tab-toggler:hover,.ibo-tab-container--extra-tab-toggler:active{color:#2c5382;background-color:#e1e7ec}.ibo-tab-container--extra-tab-toggler--tooltip-title{margin-bottom:16px}.ibo-tab-container--tab-container{padding:32px 32px;overflow-x:auto}.ibo-tab-container--tab-container-list.ibo-is-scrollable .ibo-tab-container--tab-container:not(:first-child:nth-last-child(2)) .ibo-tab-container--tab-container--label{display:block}.ibo-tab-container--tab-container-list.ibo-is-scrollable .ibo-tab-container--tab-container{min-height:auto}.ibo-tab-container--tab-container-list.ibo-is-scrollable .ibo-tab-container--tab-container:last-child:not(:only-child){min-height:60vh}.ibo-tab-container--tab-container--label{display:none;margin-bottom:20px;overflow-x:hidden}.ibo-tab-container--tab-container--label>span{position:relative;padding-left:20px;margin-left:40px;color:#929fb1}.ibo-tab-container--tab-container--label>span::before,.ibo-tab-container--tab-container--label>span::after{content:"";display:inline-block;position:absolute;top:calc(50% - (2px / 2));height:1px;width:10000px;border-top:2px solid #929fb1}.ibo-tab-container--tab-container--label>span::before{right:100%}.ibo-tab-container--tab-container--label>span::after{left:100%;margin-left:20px}.ibo-tab--temporary-remote-content{position:relative}.ibo-tab--temporary-remote-content--placeholder{position:relative;height:auto;max-height:300px;text-align:center}.ibo-tab--temporary-remote-content--placeholder>svg{max-width:calc(300px * 5.4);max-height:300px}.ibo-tab--temporary-remote-content--button{position:absolute;top:0;display:flex;justify-content:center;align-content:center;flex-direction:column;text-align:center;height:100%;width:100%;cursor:pointer;background-color:transparent;color:#404b5a}.ibo-tab--temporary-remote-content--button:hover{opacity:0.5;background-color:#212934;color:#e1e7ec}.ibo-multi-column{display:flex;flex-wrap:wrap;margin:0 -16px;row-gap:48px}.ibo-column{min-width:300px;flex-grow:1;flex-shrink:1;padding:0 16px;flex-basis:10%}.ibo-column:not(:last-child) .ibo-column:not(.ibo-without-margin){margin-bottom:48px}.ibo-mini-column{min-width:30px;flex-grow:1;flex-shrink:1;padding:0 16px;flex-basis:10%;display:flex;flex-direction:column}.ibo-mini-column>.ibo-button,.ui-dialog .ibo-mini-column>.ui-button,.ibo-mini-column>.ui-datepicker-current,.ibo-mini-column>.ui-datepicker-close{margin-left:0;margin-right:0}.ibo-mini-column:not(:last-child){margin-bottom:48px}.ibo-dashboard--top-bar{display:flex;justify-content:space-between;align-items:center;padding-bottom:20px}.ibo-dashboard--top-bar .ibo-dashboard--top-bar-toolbar{display:flex;align-items:center}.ibo-dashboard--selector{display:flex;align-items:center;margin-left:12px;margin-right:1}.ibo-dashboard--selector:hover{background-color:#f8f9fa;border-radius:4px}.ibo-dashboard--selector .selector-label{display:inline-block;margin-left:10px;margin-right:10px;vertical-align:super}.ibo-dashboard--grid{width:100%}.ibo-dashboard--grid-row{display:flex;flex-direction:row;justify-content:space-between;overflow:hidden}.ibo-dashboard--grid-row:not(:last-child){padding-bottom:calc(24px / 2)}.ibo-dashboard--grid-row:not(:first-child){padding-top:calc(24px / 2)}.ibo-dashboard--grid-column{display:flex;flex-flow:row wrap;align-items:flex-start;align-content:flex-start;width:calc(100% + (2 * 24px));margin:calc(-1 * 24px / 2) calc(-1 * 24px / 2);min-width:0}.ibo-dashboard--grid-column:not(:last-child){margin-right:0}.ibo-dashboard--grid-column:not(:first-child){margin-left:0}.ibo-dashboard--grid-column.edit_mode{margin:1px;border:2px #ccd4db dashed;width:100%;min-height:40px}.ibo-dashboard--switch{position:relative;display:inline-block;width:30px;height:24px;vertical-align:baseline}.ibo-dashboard--switch input{display:none}.ibo-dashboard--slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0}.ibo-dashboard--slider:before{content:"";font-size:0.83rem;color:#404b5a;position:absolute;right:5px;bottom:3px}.ibo-dashboard--slider:after{content:"";font-size:1.17rem;color:#dd6c20;position:absolute;left:6px;bottom:1px}input:checked+.ibo-dashboard--slider:before{content:""}input:checked+.ibo-dashboard--slider:after{content:""}.ibo-dashboard-editor--pane{flex-grow:1;padding:16px 30px 16px 15px;overflow:auto}.ibo-dashboard-editor--available-dashlet-icon{display:inline-block;height:34px;width:34px;margin:2px 5px;cursor:grab}.ibo-dashboard-editor--available-dashlet-icon:active{cursor:move}.ibo-dashboard-editor--properties,.ibo-dashboard--available-dashlets,.ibo-dashlet--properties{display:flex;flex-direction:column;padding-bottom:20px}.ibo-dashboard-editor--properties table,.ibo-dashboard--available-dashlets table,.ibo-dashlet--properties table{width:100%;text-align:left}.ibo-dashboard-editor--properties table td,.ibo-dashboard-editor--properties table th,.ibo-dashboard--available-dashlets table td,.ibo-dashboard--available-dashlets table th,.ibo-dashlet--properties table td,.ibo-dashlet--properties table th{margin-bottom:14px}.ibo-dashboard-editor--properties-title{padding-bottom:2rem}.ibo-dashboard-editor--layout-list{display:flex;justify-content:center;padding-bottom:12px}.ibo-dashboard-editor--layout-list>.ui-button{display:inline-block;height:auto;margin:0 15px 0 5px}.ibo-dashboard--available-dashlets--list{display:flex;justify-content:center;flex-wrap:wrap}#dashboard_editor{display:flex;flex-direction:row;padding:0}#dashboard_editor>.itop-dashboard{resize:horizontal;overflow:scroll;border-right:solid 1px #e1e7ec;padding:16px 15px 16px 30px}.ibo-dashboard-editor--delete-dashlet-icon{position:absolute;top:7px;right:9px;padding:2px 6px;z-index:21}.ibo-dashboard-editor .itop-dashboard a{cursor:not-allowed}.ibo-wizard-container{padding:10px 16px;background:#bee3f8;border-radius:3px;border-left:3px solid #3182ce}.ibo-object-details.ibo-has-icon.ibo-has-medallion-icon>.ibo-panel--header .ibo-panel--header-left,.ibo-object-details.ibo-has-icon.ibo-has-medallion-icon>.ibo-object-summary--header .ibo-panel--header-left{margin-left:32px;padding-left:96px}.ibo-object-details.ibo-has-icon.ibo-has-medallion-icon>.ibo-panel--header .ibo-panel--header-left .ibo-panel--icon,.ibo-object-details.ibo-has-icon.ibo-has-medallion-icon>.ibo-object-summary--header .ibo-panel--header-left .ibo-panel--icon{bottom:calc(-1 * 96px / 2 + -12px);width:96px;height:96px;min-width:96px;min-height:96px}.ibo-object-details.ibo-has-icon.ibo-has-medallion-icon>.ibo-panel--header .ibo-panel--header-left .ibo-panel--titles,.ibo-object-details.ibo-has-icon.ibo-has-medallion-icon>.ibo-object-summary--header .ibo-panel--header-left .ibo-panel--titles{padding-left:32px}.ibo-object-details--status-dot{width:10px;height:10px;min-width:10px;min-height:10px;border-radius:100%}.ibo-object-details--status-dot+.ibo-object-details--status-label{margin-left:8px}.ibo-object-details--status+.ibo-object-details--object-class{margin-left:0.5rem;display:inline-flex}.ibo-object-details--status+.ibo-object-details--object-class::before{content:"("}.ibo-object-details--status+.ibo-object-details--object-class::after{content:")"}.ibo-object-details--tag{color:#404b5a}.ibo-object-details--tag:not(:first-child){margin-left:12px}.ibo-object-details--tag-icon{margin-right:6px;color:#6e7a8a}.ibo-object-details--object-class~.ibo-object-details--tag::before,.ibo-object-details--tag~.ibo-object-details--tag::before{content:" ";display:inline-block;vertical-align:middle;margin-right:12px;width:5px;height:5px;border-radius:100%;background-color:#404b5a}.ibo-object-details.ibo-has-sticky-header>.ibo-panel--header,.ibo-object-details.ibo-has-sticky-header>.ibo-object-summary--header{}.ibo-object-details.ibo-has-sticky-header>.ibo-panel--header.ibo-is-sticking .ibo-object-details--object-class,.ibo-object-details.ibo-has-sticky-header>.ibo-is-sticking.ibo-object-summary--header .ibo-object-details--object-class{display:none}.ibo-object-details.ibo-has-sticky-header.ibo-has-icon.ibo-has-medallion-icon>.ibo-panel--header,.ibo-object-details.ibo-has-sticky-header.ibo-has-icon.ibo-has-medallion-icon>.ibo-object-summary--header{}.ibo-object-details.ibo-has-sticky-header.ibo-has-icon.ibo-has-medallion-icon>.ibo-panel--header.ibo-is-sticking .ibo-panel--header-left,.ibo-object-details.ibo-has-sticky-header.ibo-has-icon.ibo-has-medallion-icon>.ibo-is-sticking.ibo-object-summary--header .ibo-panel--header-left{padding-left:48px}.ibo-object-details.ibo-has-sticky-header.ibo-has-icon.ibo-has-medallion-icon>.ibo-panel--header.ibo-is-sticking .ibo-panel--header-right,.ibo-object-details.ibo-has-sticky-header.ibo-has-icon.ibo-has-medallion-icon>.ibo-is-sticking.ibo-object-summary--header .ibo-panel--header-right{padding-right:8px}.ibo-object-details.ibo-has-sticky-header.ibo-has-icon.ibo-has-medallion-icon>.ibo-panel--header.ibo-is-sticking .ibo-panel--titles,.ibo-object-details.ibo-has-sticky-header.ibo-has-icon.ibo-has-medallion-icon>.ibo-is-sticking.ibo-object-summary--header .ibo-panel--titles{padding-left:32px}.ibo-object-summary.ibo-has-medallion-icon .ibo-panel--titles{padding-left:16px}.ibo-object-summary>.ibo-panel--body{display:flex;flex-direction:column;padding:0;max-height:40vh;box-shadow:0 3px 6px rgba(0, 0, 0, 0.1), 0 10px 20px rgba(0, 0, 0, 0.15)}.ibo-object-summary--header{margin:8px 0 0 0;padding:8px 0;background-color:#f8f9fa;border-bottom:solid 1px #ccd4db}.ibo-object-summary--header .ibo-panel--icon{overflow:hidden;background-color:#f8f9fa;border:1px solid #90a4ae;border-radius:100%}.ibo-object-summary--header .ibo-panel--header-left{margin-left:16px}.ibo-object-summary--header .ibo-panel--header-right{align-self:start;margin-right:16px;margin-left:8px}.ibo-object-summary--body{overflow:auto}.ibo-object-summary--content--attributes{display:table;width:calc(100% - (2 * 16px));margin:16px 16px 24px 16px}.ibo-object-summary--content--attributes--code,.ibo-object-summary--content--attributes--value{display:table-cell}.ibo-activity-panel{position:relative;display:flex;flex-direction:column;width:480px;height:100%;transition:width 0.2s ease-in-out}.ibo-activity-panel.ibo-is-expanded{width:60vw}.ibo-activity-panel.ibo-is-expanded .ibo-activity-panel--expand-icon{display:none}.ibo-activity-panel:not(.ibo-is-expanded) .ibo-activity-panel--reduce-icon{display:none}.ibo-activity-panel.ibo-is-closed{width:32px}.ibo-activity-panel.ibo-is-closed .ibo-activity-panel--header,.ibo-activity-panel.ibo-is-closed .ibo-activity-panel--body,.ibo-activity-panel.ibo-is-closed .ibo-activity-panel--add-caselog-entry-button{display:none}.ibo-activity-panel.ibo-is-closed .ibo-activity-panel--closed-cover{display:inherit}.ibo-activity-panel--header{position:relative;background-color:#f8f9fa}.ibo-activity-panel--header .ibo-activity-panel--togglers a{color:#404b5a}.ibo-activity-panel--togglers{display:flex;align-items:center}.ibo-activity-panel--actions{display:flex;align-items:center;flex-grow:0;position:sticky;padding-right:16px;background-color:#f8f9fa;color:#929fb1}.ibo-activity-panel--actions:hover{color:#404b5a}.ibo-activity-panel--actions>*:not(:first-child){margin-left:0.75rem}.ibo-activity-panel--tabs-togglers{display:flex;align-items:center;justify-content:safe center;flex-grow:1;padding-left:48px;overflow-x:auto}.ibo-activity-panel--tab-toggler.ibo-is-active .ibo-activity-panel--tab-title{background-color:#e1e7ec}.ibo-activity-panel--tab-toggler.ibo-is-active .ibo-activity-panel--tab-title-messages-count{display:none}.ibo-activity-panel--tab-toggler.ibo-is-draft .ibo-activity-panel--tab-title-draft-indicator{display:initial}.ibo-activity-panel--tab-toggler-for-caselog-1 .ibo-activity-panel--tab-title-decoration{background-color:#689f38}.ibo-activity-panel--tab-toggler-for-caselog-2 .ibo-activity-panel--tab-title-decoration{background-color:#b83280}.ibo-activity-panel--tab-toggler-for-caselog-3 .ibo-activity-panel--tab-title-decoration{background-color:#f6ae55}.ibo-activity-panel--tab-toggler-for-caselog-4 .ibo-activity-panel--tab-title-decoration{background-color:#3182ce}.ibo-activity-panel--tab-toggler-for-caselog-5 .ibo-activity-panel--tab-title-decoration{background-color:#80deea}.ibo-activity-panel--tab-toggler-for-caselog-6 .ibo-activity-panel--tab-title-decoration{background-color:#c5e1a5}.ibo-activity-panel--tab-toggler-for-caselog-7 .ibo-activity-panel--tab-title-decoration{background-color:#fbb6ce}.ibo-activity-panel--tab-title{padding:8px 16px}.ibo-activity-panel--tab-title:hover{background-color:#e1e7ec}.ibo-activity-panel--tab-title-decoration{display:inline-flex;margin-right:8px;width:12px;height:12px;border-radius:3px}.ibo-activity-panel--tab-title-messages-count{display:inline-block;margin-left:8px;background-color:#e1e7ec;padding:0 4px;border-radius:3px}.ibo-activity-panel--tab-title-messages-count[data-messages-count="0"]{display:none}.ibo-activity-panel--tab-title-draft-indicator{display:none;margin-left:8px}.ibo-activity-panel--tab-title-text{max-width:100px}.ibo-activity-panel--tab-toolbar{display:none;flex-direction:column;padding-left:10px;padding-right:10px;background-color:#e1e7ec}.ibo-activity-panel--tab-toolbar.ibo-is-active{display:flex}.ibo-activity-panel--tab-toolbar-actions{justify-content:space-between;flex-wrap:nowrap;margin:4px 0;height:32px}.ibo-activity-panel--tab-toolbar-left-actions .ibo-activity-panel--tab-toolbar-action:not(:first-child)::before{content:"-";margin:0 8px}.ibo-activity-panel--tab-toolbar-middle-actions .ibo-activity-panel--tab-toolbar-action>input{margin-right:8px}.ibo-activity-panel--tab-toolbar-middle-actions .ibo-activity-panel--tab-toolbar-action:not(:first-child){margin-left:18px}.ibo-activity-panel--tab-toolbar-right-actions .ibo-activity-panel--tab-toolbar-info{color:#212934}.ibo-activity-panel--tab-toolbar-right-actions .ibo-activity-panel--tab-toolbar-info>.ibo-activity-panel--tab-toolbar-info-icon{margin-left:8px}.ibo-activity-panel--tab-toolbar-right-actions .ibo-activity-panel--tab-toolbar-info:not(:first-child){margin-left:16px}.ibo-activity-panel--tab-toolbar-action{position:relative;color:#212934}.ibo-activity-panel--filter{cursor:pointer}.ibo-activity-panel--filter-options-toggler{padding-left:0.5rem;color:#212934}.ibo-activity-panel--filter-options-toggler.ibo-is-closed{transform:rotateX(180deg)}.ibo-activity-panel--filter-options-toggler.ibo-is-closed+.ibo-activity-panel--filter-options{display:none}.ibo-activity-panel--filter-options{position:absolute;z-index:1;display:flex;flex-direction:column;top:24px;left:-12px;max-width:200px;padding:8px 12px;background-color:#e1e7ec;border-radius:3px}.ibo-activity-panel--filter-option{cursor:pointer}.ibo-activity-panel--filter-option:not(:first-child){margin-top:8px}.ibo-activity-panel--filter-option-input{margin-right:0.5rem}.ibo-activity-panel--body{flex-grow:1;overflow:auto;padding:16px 16px}.ibo-activity-panel--body--placeholder{margin-top:16px}.ibo-activity-panel--body--placeholder-image>svg{width:250px;height:inherit}.ibo-activity-panel--body--placeholder-hint{margin-top:16px;color:#404b5a}.ibo-activity-panel--add-caselog-entry-button{position:absolute;z-index:1;right:12px;top:88px;width:36px;height:36px;background-color:#dd6c20;color:white;border-radius:100%;box-shadow:0 1px 2px rgba(0, 0, 0, 0.25), 0 1px 3px rgba(0, 0, 0, 0.12)}.ibo-activity-panel--add-caselog-entry-button>i{text-align:center;height:100%;width:100%;font-size:1.33rem;line-height:33px}.ibo-activity-panel--add-caselog-entry-button:hover{color:white;background-color:#ea7d1e;box-shadow:0 2px 4px rgba(0, 0, 0, 0.12), 0 3px 6px rgba(0, 0, 0, 0.15)}.ibo-activity-panel--add-caselog-entry-button:active{color:white;background-color:#c05621}.ibo-activity-panel--add-caselog-entry-button.ibo-is-hidden{display:none}.ibo-activity-panel .ibo-activity-panel--entry-forms-confirmation-dialog{display:none}.ibo-activity-panel--entry-forms-confirmation-explanation{margin-bottom:16px}.ibo-activity-panel--entry-forms-confirmation-preference-input{margin-right:0.5rem}.ibo-activity-panel--closed-cover{display:none;position:absolute;z-index:2;top:0;bottom:0;left:0;right:0;background-color:#f8f9fa;cursor:pointer}.ibo-activity-panel--closed-content-container{transform:rotateZ(-90deg);white-space:nowrap}.ibo-activity-panel--open-icon{margin-left:0.75rem}.ibo-caselog-entry-form{display:block;width:100%;background-color:#e1e7ec}.ibo-caselog-entry-form.ibo-is-closed{display:none}.ibo-caselog-entry-form--actions{display:flex;justify-content:space-between;margin-top:8px;margin-bottom:8px}.ibo-caselog-entry-form--lock-indicator{margin-top:12px}.ibo-caselog-entry-form--lock-icon{width:32px;min-width:32px;height:32px;min-height:32px;color:#fcfcfd;background-color:#404b5a;border-radius:100%}.ibo-caselog-entry-form--lock-message{margin-left:1rem}.ibo-caselog-entry-form--action-buttons--main-actions{}.ibo-caselog-entry-form--action-buttons--main-actions>.ibo-popover-menu,.ibo-caselog-entry-form--action-buttons--main-actions>.ui-menu,.ibo-caselog-entry-form--action-buttons--main-actions>.ui-multiselect-menu,.ibo-caselog-entry-form--action-buttons--main-actions>.ibo-input-select-icon--menu,.graph_config .toolkit_menu.graph>ul>li .ibo-caselog-entry-form--action-buttons--main-actions>ul{z-index:1}.ibo-activity-panel--entry-group:not(:last-child){margin-bottom:24px}.ibo-activity-entry{display:flex;flex-direction:row;align-items:flex-end}.ibo-activity-entry:not(:last-child) .ibo-activity-entry--medallion{visibility:hidden}.ibo-activity-entry:not(:last-child) .ibo-activity-entry--sub-information{margin-bottom:4px}.ibo-activity-entry.ibo-is-current-user{flex-direction:row-reverse;min-width:min-content}.ibo-activity-entry.ibo-is-current-user .ibo-activity-entry--medallion{margin-right:initial;margin-left:8px}.ibo-activity-entry.ibo-is-current-user .ibo-activity-entry--information{margin-right:0;margin-left:40px}.ibo-activity-entry.ibo-is-current-user .ibo-activity-entry--main-information{background-color:#ebf8ff}.ibo-activity-entry.ibo-is-current-user .ibo-activity-entry--sub-information{text-align:right}.ibo-activity-entry.ibo-is-current-user:last-child .ibo-activity-entry--main-information{border-bottom-right-radius:0;border-bottom-left-radius:5px}.ibo-activity-entry:not(.ibo-is-current-user){}.ibo-activity-entry:not(.ibo-is-current-user) .ibo-activity-entry--information{margin-right:40px;margin-left:0}.ibo-activity-entry:not(.ibo-is-current-user):last-child .ibo-activity-entry--main-information{border-bottom-right-radius:5px;border-bottom-left-radius:0}.ibo-activity-entry.ibo-is-closed .ibo-activity-entry--main-information{max-height:48px;overflow:hidden;cursor:pointer}.ibo-activity-entry.ibo-is-closed .ibo-activity-entry--main-information::after{content:"...";position:absolute;top:30px;left:0;padding-left:16px;width:100%;height:100%;background-color:inherit}.ibo-activity-entry--medallion{margin-right:8px;margin-bottom:18px;min-width:32px;width:32px;min-height:32px;height:32px;overflow:hidden;border-radius:100%}.ibo-activity-entry--medallion.ibo-has-image{background-color:#ebf8ff;box-shadow:inset 0 1px 2px 0 rgba(0, 0, 0, 0.25)}.ibo-activity-entry--medallion:not(.ibo-has-image){background-color:#546e7a;color:white;border:1px solid #e1e7ec}.ibo-activity-entry--medallion .ibo-activity-entry--author-picture{max-height:100%}.ibo-activity-entry--main-information{position:relative;display:flex;flex-direction:row;align-items:baseline;padding:12px 16px;color:#404b5a;background-color:#e1e7ec;border-radius:5px}.ibo-activity-entry--main-information-icon{margin-right:16px;color:#6e7a8a;font-size:1.33rem}.ibo-activity-entry--main-information-content{flex-grow:1;word-break:break-word}.ibo-activity-entry--main-information-content a{color:#2b6bb0}.ibo-activity-entry--main-information-content a:hover{color:#2a4265}.ibo-activity-entry--main-information-content a:active,.ibo-activity-entry--main-information-content a:focus{color:#2a4265}.ibo-activity-entry--sub-information{margin-top:4px;text-align:left;color:#6e7a8a}.ibo-activity-entry--sub-information>*:not(:last-child):after{content:" ";display:inline-block;vertical-align:middle;margin-left:0.5rem;margin-right:0.5rem;width:4px;height:4px;border-radius:100%;background-color:#929fb1}.ibo-activity-panel--load-more-entries-container{position:relative}.ibo-activity-panel--load-more-entries-container:hover .ibo-activity-panel--load-all-entries{margin-left:84px}.ibo-activity-panel--load-more-entries-container:not(:hover) .ibo-activity-panel--load-all-entries{visibility:hidden}.ibo-activity-panel--load-entries-button{width:32px;height:32px;border-radius:100%;background-color:#e1e7ec;border:1px solid #ccd4db}.ibo-activity-panel--load-more-entries{z-index:1}.ibo-activity-panel--load-all-entries{position:absolute;z-index:0;top:0;margin-left:0;transition:all 0.1s ease-in-out}.ibo-caselog-entry{}.ibo-caselog-entry .ibo-activity-entry--main-information{padding-top:12px;padding-bottom:12px}.ibo-caselog-entry .ibo-activity-entry--main-information-icon{display:none}.ibo-caselog-entry .ibo-activity-entry--main-information::before{content:"";position:absolute;top:0;bottom:0;width:3px}.ibo-caselog-entry:not(.ibo-is-current-user) .ibo-activity-entry--main-information::before{left:0;border-top-left-radius:5px;border-bottom-left-radius:5px}.ibo-caselog-entry:not(.ibo-is-current-user):last-child .ibo-activity-entry--main-information::before{border-bottom-left-radius:0}.ibo-caselog-entry.ibo-is-current-user .ibo-activity-entry--main-information::before{right:0;border-top-right-radius:5px;border-bottom-right-radius:5px}.ibo-caselog-entry.ibo-is-current-user:last-child .ibo-activity-entry--main-information::before{border-bottom-right-radius:0}.ibo-caselog-entry.ibo-is-closed.ibo-is-current-user .ibo-activity-entry--main-information::after{width:calc(100% - 3px)}.ibo-caselog-entry.ibo-is-closed:not(.ibo-is-current-user) .ibo-activity-entry--main-information::after{margin-left:3px}.ibo-caselog-entry--entry-for-caselog-1 .ibo-activity-entry--main-information::before{background-color:#689f38}.ibo-caselog-entry--entry-for-caselog-2 .ibo-activity-entry--main-information::before{background-color:#b83280}.ibo-caselog-entry--entry-for-caselog-3 .ibo-activity-entry--main-information::before{background-color:#f6ae55}.ibo-caselog-entry--entry-for-caselog-4 .ibo-activity-entry--main-information::before{background-color:#3182ce}.ibo-caselog-entry--entry-for-caselog-5 .ibo-activity-entry--main-information::before{background-color:#80deea}.ibo-caselog-entry--entry-for-caselog-6 .ibo-activity-entry--main-information::before{background-color:#c5e1a5}.ibo-caselog-entry--entry-for-caselog-7 .ibo-activity-entry--main-information::before{background-color:#fbb6ce}.ibo-transition-entry--original-state-label{color:#404b5a;text-decoration:line-through}a.ibo-edits-entry--short-description{position:relative;display:block;color:inherit}.ibo-edits-entry--long-description-toggler-icon{position:absolute;top:3px;right:0;transition:all 0.2s ease-in-out}.ibo-edits-entry--long-description{display:none;margin-top:8px;list-style:inside}.ibo-edits-entry:not(.ibo-is-closed) .ibo-edits-entry--long-description-toggler-icon{transform:rotateX(180deg)}.ibo-edits-entry:not(.ibo-is-closed) .ibo-edits-entry--long-description{display:block}a.ibo-notification-entry--short-description{color:inherit}.ibo-notification-entry--long-description-toggler-icon{margin-left:12px;transition:all 0.2s ease-in-out}.ibo-notification-entry--long-description{display:none;margin-top:8px;list-style:inside}.ibo-notification-entry:not(.ibo-is-closed) .ibo-notification-entry--long-description-toggler-icon{transform:rotateX(180deg)}.ibo-notification-entry:not(.ibo-is-closed) .ibo-notification-entry--long-description{display:block}.ibo-bulk--bulk-modify--incompatible-attribute:before{margin-right:4px;content:"";color:#429ae1}#form_part_csv_options:has(#ibo-sanitize-excel-export--input:checked) #ibo-sanitize-excel-export--alert,#form_part_xlsx_options:has(#ibo-sanitize-excel-export--input:checked) #ibo-sanitize-excel-export--alert{display:none}.ibo-block-csv textarea{width:100%;min-height:10em;margin-top:10px}.ibo-block-list--empty-text,.ibo-block-list--create-action{text-align:center}.ibo-block-list--create-icon{margin-right:0.5rem}.ibo-linked-set--bulk-tooltip-info:before{margin-right:4px;content:"";color:#429ae1}.ibo-table-preview{margin-top:20px;overflow-x:auto}.ibo-table-preview th{position:relative;padding:4px 24px 4px 4px;border-width:1px 1px 0;border-style:groove groove none;background:#f2f2f2}.ibo-table-preview td{padding-right:4px;padding-left:4px;border-width:0 1px;border-style:none groove}.ibo-table-preview tr:last-child td{border-bottom-width:1px;border-bottom-style:groove}.ibo-preview-header{margin-bottom:4px}.ibo-table-preview--remove-column{position:absolute;top:8px;right:8px;display:inline-block;cursor:pointer;font-size:8px}#form_part_interactive_fields_xlsx,#form_part_interactive_fields_csv,#form_part_interactive_fields_pdf{margin-top:24px}.ibo-welcome-popup--dialog.ui-dialog-content{padding:0 0;height:auto !important;max-height:80vh !important}.ibo-welcome-popup--messages-stack{min-width:300px;max-width:300px;padding:24px 16px;overflow-y:auto;background-color:#f8f9fa}.ibo-welcome-popup--messages-stack>*:not(:first-child){margin-top:12px}.ibo-welcome-popup--stack-item{padding:12px 16px;background-color:white;border:1px solid #d5dde5}.ibo-welcome-popup--stack-item.ibo-is-active{border-color:#929fb1}.ibo-welcome-popup--stack-item.ibo-is-acknowledged{opacity:0.6}.ibo-welcome-popup--stack-item.ibo-is-acknowledged.ibo-is-active{opacity:1}.ibo-welcome-popup--stack-item-icon{width:32px;height:32px;min-width:32px;min-height:32px;margin-right:12px;border-width:1px}.ibo-welcome-popup--message-content-wrapper{overflow:auto}.ibo-welcome-popup--message-content{display:flex;justify-content:space-between;align-items:center;padding:32px 48px}.ibo-welcome-popup--message-content .ibo-welcome-popup--message-illustration{margin-left:48px}.ibo-welcome-popup--message-content:not(.ibo-is-active){display:none}.ibo-welcome-popup--message-content.ibo-is-illustration-on-left-side{flex-direction:row-reverse}.ibo-welcome-popup--message-content.ibo-is-illustration-on-left-side .ibo-welcome-popup--message-illustration{margin-left:unset;margin-right:48px}.ibo-welcome-popup--message-title{margin-bottom:32px}.ibo-welcome-popup--message-illustration{display:flex;min-width:256px;aspect-ratio:1;background-size:contain}.ibo-welcome-popup--message-illustration>svg{height:auto}.ibo-user-rights{padding:4px 12px;border-radius:4px}.ibo-user-rights.ibo-is-success{background-color:#dcedc8;color:#235816;border:1px solid #8ac34a}.ibo-user-rights.ibo-is-failure{background-color:#fce8e8;color:#491d1d;border:1px solid #f56565}:root{--ibo-dm-class--User--main-color: #546e7a;--ibo-dm-class--User--complementary-color: white}.ibo-dm-class--User{--ibo-main-color: #546e7a;--ibo-main-color--100: #eaeef0;--ibo-main-color--900: #1f292d;--ibo-complementary-color: white}.ibo-dm-class-alt--User{--ibo-main-color: white;--ibo-complementary-color: #546e7a}:root{--ibo-dm-enum--User-status-enabled--main-color: #689f38;--ibo-dm-enum--User-status-enabled--complementary-color: white}.ibo-dm-enum--User-status-enabled{--ibo-main-color: #689f38;--ibo-main-color--100: #edf6e5;--ibo-main-color--900: #253914;--ibo-complementary-color: white}.ibo-dm-enum-alt--User-status-enabled{--ibo-main-color: white;--ibo-complementary-color: #689f38}:root{--ibo-dm-enum--User-status-disabled--main-color: #f6ae55;--ibo-dm-enum--User-status-disabled--complementary-color: white}.ibo-dm-enum--User-status-disabled{--ibo-main-color: #f6ae55;--ibo-main-color--100: #fdefdd;--ibo-main-color--900: #492a04;--ibo-complementary-color: white}.ibo-dm-enum-alt--User-status-disabled{--ibo-main-color: white;--ibo-complementary-color: #f6ae55}:root{--ibo-dm-class--Action--main-color: #546e7a;--ibo-dm-class--Action--complementary-color: white}.ibo-dm-class--Action{--ibo-main-color: #546e7a;--ibo-main-color--100: #eaeef0;--ibo-main-color--900: #1f292d;--ibo-complementary-color: white}.ibo-dm-class-alt--Action{--ibo-main-color: white;--ibo-complementary-color: #546e7a}:root{--ibo-dm-enum--Action-status-enabled--main-color: #689f38;--ibo-dm-enum--Action-status-enabled--complementary-color: white}.ibo-dm-enum--Action-status-enabled{--ibo-main-color: #689f38;--ibo-main-color--100: #edf6e5;--ibo-main-color--900: #253914;--ibo-complementary-color: white}.ibo-dm-enum-alt--Action-status-enabled{--ibo-main-color: white;--ibo-complementary-color: #689f38}:root{--ibo-dm-enum--Action-status-disabled--main-color: #e1e7ec;--ibo-dm-enum--Action-status-disabled--complementary-color: #6e7a8a}.ibo-dm-enum--Action-status-disabled{--ibo-main-color: #e1e7ec;--ibo-main-color--100: #e9eef1;--ibo-main-color--900: #1e272f;--ibo-complementary-color: #6e7a8a}.ibo-dm-enum-alt--Action-status-disabled{--ibo-main-color: #6e7a8a;--ibo-complementary-color: #e1e7ec}:root{--ibo-dm-enum--Action-status-test--main-color: #f6ae55;--ibo-dm-enum--Action-status-test--complementary-color: white}.ibo-dm-enum--Action-status-test{--ibo-main-color: #f6ae55;--ibo-main-color--100: #fdefdd;--ibo-main-color--900: #492a04;--ibo-complementary-color: white}.ibo-dm-enum-alt--Action-status-test{--ibo-main-color: white;--ibo-complementary-color: #f6ae55}.ibo-about-box--top-part{display:flex;flex-direction:row;align-content:center}.ibo-about-box--top-part>div{padding:16px 12px;margin:auto auto;width:50%}:root{--ibo-body-text-color: #212934;--ibo-body-background-color: #f2f2f2}html{height:100vh}body{display:flex;height:100vh;color:var(--ibo-body-text-color);background-color:var(--ibo-body-background-color)}#ibo-navigation-menu{z-index:20}#ibo-page-container{position:relative;z-index:10;height:100%;overflow:auto;flex-grow:1;display:flex;flex-direction:column}#ibo-top-bar,#ibo-main-content{padding-left:36px;padding-right:36px}#ibo-top-container{z-index:20;position:sticky;top:0;left:0;right:0}#ibo-center-container{position:relative;z-index:10;flex-grow:1;overflow:hidden}#ibo-center-container>*{height:100%}#ibo-main-content{padding-top:16px;padding-bottom:16px;overflow:auto}#ibo-main-content>.ibo-panel{margin-left:auto;margin-right:auto}.ibo-preferences--user-preferences--picture-placeholder{display:flex;flex-direction:row;flex-wrap:wrap}.ibo-preferences--user-preferences--picture-placeholder--image{height:54px;width:54px;border-radius:100%;margin:12px;border:solid 3px #d5dde5}.ibo-preferences--user-preferences--picture-placeholder--image>img{border-radius:100%;background-color:#d5dde5}.ibo-preferences--user-preferences--picture-placeholder--image.ibo-is-active{border-color:#2c5382}.ibo-preferences--user-preferences--picture-placeholder--image:hover{border-color:#3182ce}#ibo-form-for-user-interface-preferences>.ibo-keyboard-shortcut--shortcut{display:table;width:100%}#ibo-form-for-user-interface-preferences>.ibo-keyboard-shortcut--shortcut>*:not(.ibo-button){width:30%;display:table-cell}.ibo-keyboard-shortcut--input,.ibo-keyboard-shortcut--input:focus{display:inline-block;width:auto;text-transform:capitalize;text-align:center;color:#404b5a;background-color:transparent;border:1px solid #aebecd;border-bottom:2px solid #aebecd;border-radius:3px;padding:2px 4px;margin-bottom:5px}.ibo-keyboard-shortcut--input.ibo-is-focus,.ibo-keyboard-shortcut--input:focus.ibo-is-focus{text-transform:none;color:#9c4221;border-color:#dd6c20}#ibo-favorite-organizations .ibo-toolbar{float:right;vertical-align:top}#ibo-favorite-organizations .ibo-datatable--toolbar{padding-top:3px}#ibo-attachment--upload-file .ibo-input-file-select--container{display:inline-block}.ibo-attachment--datatable--icon-preview{max-height:44px;max-width:44px}.ibo-attachment--datatable tbody tr td{vertical-align:middle}.ibo-attachment--upload-file--drop-zone-hint{display:none}.ibo-drag-in{border:2px #ccd4db dashed}.ibo-drag-in .ibo-attachment--upload-file--drop-zone-hint{display:flex;flex-direction:column;justify-content:center;align-items:center;width:100%;max-height:200px;margin:22px 0;color:#6e7a8a}.ibo-drag-in .ibo-attachment--upload-file--drop-zone-hint>svg{margin-bottom:5px}.ibo-drag-in #ibo-attachment--upload-file--upload-button-container{display:none}.ibo-tab-container--tab-header.ibo-drag-in,.ibo-drag-in.ibo-tab-container--extra-tabs-container{border:none;background-color:#bee3f8;color:#2c5382}.ibo-tab-container--tab-header.ibo-drag-in>a::after,.ibo-drag-in.ibo-tab-container--extra-tabs-container>a::after{content:"";padding-left:8px;color:#3182ce}.itop-simple-graph{margin-top:10px;border:1px dotted transparent;border-radius:5px}.itop-simple-graph.ibo-has-focus{border:1px dotted #404b5a}.graph_zoom{display:flex;float:right;align-items:center}.graph_zoom_slider{height:1.1em;display:inline-block;width:10em}.graph_zoom_plus,.graph_zoom_minus{cursor:pointer;display:inline-block;margin-left:0.5em;margin-right:0.5em}.graph_config{display:flex;align-items:center;flex-wrap:wrap}.graph_config .toolkit_menu.graph>ul>li{position:relative}.graph_config .toolkit_menu.graph>ul>li ul{z-index:1;position:absolute;display:none}.graph_separator{flex-grow:1}.ibo-simple-graph--grouping-threshold--container,.ibo-simple-graph--additional-context--container{margin-right:0.3em;display:flex;align-items:center}.ibo-simple-graph--grouping-threshold--container>*,.ibo-simple-graph--additional-context--container>*{margin-right:1em}#graph_grouping_threshold{width:auto;padding-right:0}.ibo-display-graph--search-box .sf_criterion_area{display:flex;flex-direction:column}.ibo-display-graph--search-box .sf_criterion_row{display:flex;flex-wrap:wrap;align-items:center}.ibo-display-graph--search-box .sf_criterion_row>div{align-items:center;display:flex;padding:0 15px}.ibo-display-graph--search-box .sf_criterion_row>div>input{margin-right:10px}.ibo-display-graph--search-box .sf_criterion_row>div .ibo-medallion-icon{display:flex;align-items:center}.ibo-display-graph--search-box #ReloadMovieBtn{align-self:flex-end}#impacted_objects_lists>div~div{margin-top:24px}#impacted_objects_lists_placeholder,#impacted_groups_placeholder{height:256px}.ibo-audit--audit-category--panel .ibo-panel--body tr.ibo-is-red td:last-of-type:before{background-color:#c53030}.ibo-audit--audit-category--panel .ibo-panel--body tr.ibo-is-orange td:last-of-type:before{background-color:#c05621}.ibo-audit--audit-category--panel .ibo-panel--body tr.ibo-is-green td:last-of-type:before{background-color:#558b2f}.ibo-audit--audit-category--panel .ibo-panel--body{padding:10px 16px}.ibo-audit--audit-category--panel .ibo-panel--body .ibo-datatable td:not(:nth-child(1)),.ibo-audit--audit-category--panel .ibo-panel--body .ibo-datatable th:not(:nth-child(1)){text-align:right;width:100px}.ibo-audit--audit-category--panel .ibo-panel--body .ibo-datatable--toolbar{display:none}.ibo-audit--audit-category--panel .ibo-panel--body tr td:last-of-type:before{content:"";height:12px;width:12px;border-radius:100%;display:inline-block;margin-right:5px;vertical-align:middle}.ibo-audit--dashboard{padding:18px 0}.ibo-dashboard--grid-row+.ibo-audit--error-alert{margin-top:24px}.ibo-audit--audit-line--csv-download{height:2.5em;vertical-align:middle}.ibo-data-synchro-source--replicas-status.ibo-is-grey{color:#212934;background-color:#ccd4db}.ibo-data-synchro-source--replicas-status.ibo-is-orange{color:#7b341e;background-color:#fbd38d}.ibo-data-synchro-source--replicas-status.ibo-is-bluegrey{color:#263238;background-color:#b0bec5}.ibo-data-synchro-source--replicas-status.ibo-is-red{color:#742a2a;background-color:#feb2b2}.ibo-data-synchro-source--replicas-status.ibo-is-blue{color:#2a4265;background-color:#bee3f8}.ibo-data-synchro-source--replicas-status.ibo-is-green{color:#33691e;background-color:#dcedc8}.ibo-data-synchro-source--replicas-status.ibo-is-cyan{color:#006164;background-color:#c9eef2}.ibo-data-synchro-source--replicas-status-separator{border-top:white}.ibo-data-synchro-source--replicas-status.ibo-is-light{opacity:0.5}.ibo-data-synchro-source--replicas-status.ibo-is-light:hover{opacity:1}.synoptics tr td{padding:10px;min-width:200px;vertical-align:middle;text-align:center}.synoptics tr td.arrow{min-width:100px;border-top:2px solid #fcfcfd}.ibo-data-synchro-source--replicas-status--warning{margin:0 5px 0 8px}.ibo-datamodel-viewer--details .ibo-datamodel-viewer--empty{display:flex;flex-direction:column;align-items:center}.ibo-datamodel-viewer--details .ibo-datamodel-viewer--empty svg{width:max(20%, 384px)}.ibo-datamodel-viewer--breadcrumb{margin:4px 0}.ibo-datamodel-viewer--breadcrumb .ibo-button,.ibo-datamodel-viewer--breadcrumb .ui-dialog .ui-button,.ui-dialog .ibo-datamodel-viewer--breadcrumb .ui-button,.ibo-datamodel-viewer--breadcrumb .ui-datepicker-current,.ibo-datamodel-viewer--breadcrumb .ui-datepicker-close{text-transform:none}.ibo-datamodel-viewer--classname{color:#546e7a}.ibo-datamodel-viewer--tag--category{color:#37474f}.ibo-datamodel-viewer--tag--category .ibo-object-details--tag-icon{color:#546e7a}.ibo-datamodel-viewer--icon--abstract:after{content:"A";display:inline-flex;justify-content:center;align-items:center;width:15px;height:15px;line-height:14px;border-radius:50%;border:1px solid #00bbd4;color:white;background-color:#00bbd4}.ibo-datamodel-viewer--parent--spacer{padding:0 8px}.ibo-datamodel-viewer--classes-list .selectize-input,.ibo-datamodel-viewer--classes-list .ibo-quick-create--input.selectize-control.single .selectize-input.input-active,.ibo-quick-create--input.selectize-control.single .ibo-datamodel-viewer--classes-list .selectize-input.input-active{background-color:white !important;background-image:none !important;color:#404b5a;box-shadow:none !important;border-color:#aebecd !important}#ibo-datamodel-viewer--attributes-table>tbody tr td:first-child{width:3px}.ibo-datamodel-viewer--origin-cell{vertical-align:middle}.ibo-datamodel-viewer--origin-cell>div{height:8px;width:8px;border-radius:100%}.ibo-datamodel-viewer--classes-list{position:relative;height:100%;width:384px;padding-left:24px;padding-top:8px;overflow-y:scroll}.ibo-datamodel-viewer--lifecycle--code{color:#6e7a8a}.ibo-datamodel-viewer--lifecycle--stimuli{color:#2a4265}.ibo-datamodel-viewer--lifecycle--attribute-option{color:#702459}.dataModelSchema g{cursor:pointer}.dataModelSchema g:hover rect:not(.liseret){fill:#ccd4db}.dataModelSchema text{fill:#212934;text-anchor:middle}#selfreferencing:hover~g>.selfattr{fill:#ccd4db}.tooltipD3{position:fixed;text-align:center;background:white;border:1px solid #6e7a8a;border-radius:3px;pointer-events:none;fill:#212934;text-anchor:middle}.tooltipD3 i{font-size:1rem}.tooltipD3 span{margin:3px}#tooltipD3_top{border-bottom:1px solid #6e7a8a;padding:3px}.ibo-datamodel-viewer--lifecycle-image{margin-bottom:16px}#tabs1-import .ibo-field--label{max-width:50%}div.ibo-csv-import--cell-modified{font-weight:bold;color:#2b6bb0}div.ibo-csv-import--cell-error{font-weight:bold;color:#c53030}div.ibo-csv-import--cell-message{padding-top:3px}tr.ibo-csv-import--row-unchanged td{border-bottom:1px #ccd4db solid}.wizContainer table tr.ibo-csv-import--row-error td{border-bottom:1px #ccd4db solid;background-color:#fed7d7}tr.ibo-csv-import--row-modified td{border-bottom:1px #ccd4db solid}tr.ibo-csv-import--row-added td{border-bottom:1px #ccd4db solid}.ibo-csv-import--download-file{font-size:4em;color:#f6ae55;margin:20px}.ibo-global-search--result--title>img{max-height:48px;max-width:48px;margin-right:8px}.ibo-run-query--highlight{background-color:#fbd38d}.ibo-oauth-wizard .ibo-panel--body .ibo-oauth-wizard--form--container{display:flex;flex-direction:row;flex-grow:1}.ibo-oauth-wizard .ibo-panel--body .ibo-oauth-wizard--illustration svg{max-height:384px}#ibo-oauth-wizard--conf--result{white-space:pre-wrap}.ibo-notifications--view-all--container{display:grid;grid-gap:24px}.ibo-notifications--view-all--container .ibo-object-summary .ibo-panel--title{font-size:1.5rem}.ibo-notifications--view-all--container .ibo-object-summary .ibo-panel--toolbar{min-width:96px}.ibo-notifications--view-all--container .ibo-object-summary>.ibo-panel--body{box-shadow:none;max-height:400px}.ibo-notifications--view-all--container .ibo-object-summary+.ibo-object-summary{margin-top:0}@media screen and (max-width:768px){.ibo-notifications--view-all--container{grid-template-columns:repeat(1, 1fr)}}@media screen and (min-width:1024px){.ibo-notifications--view-all--container{grid-template-columns:repeat(2, 1fr)}}@media screen and (min-width:1408px){.ibo-notifications--view-all--container{grid-template-columns:repeat(3, 1fr)}}.ibo-notifications--view-all--toolbar{justify-content:space-between}.ibo-notifications--view-all--toggler{display:flex;align-content:center}.ibo-notifications--view-all--item--read .ibo-panel--body::before{background-color:#e1e7ec}.ibo-notifications--view-all--item--unread .ibo-panel--body::before{background-color:#e53e3e}.ibo-notifications--view-all--container .ibo-notifications--view-all--read-action,.ibo-notifications--view-all--container .ibo-notifications--view-all--unread-action{margin-left:0 !important}.ibo-notifications--view-all--item--read .ibo-notifications--view-all--read-action{display:none}.ibo-notifications--view-all--item--unread .ibo-notifications--view-all--unread-action{display:none}.ibo-notifications--view-all--empty{flex-direction:column;margin-top:96px}.ibo-notifications--view-all--empty svg{max-width:30%;height:auto}.ibo-input-select--notification-item{display:flex !important;flex-direction:row}.ibo-input-select--notification-item--mixed-value{font-size:1rem;color:#9c4221;margin-left:4px}.ibo-alert+.ibo-alert{margin-top:4px}.ibo-alert+.ibo-block:not(.ibo-alert){margin-top:16px}.ibo-button+.ibo-button,.ui-dialog .ui-button+.ibo-button,.ui-dialog .ui-button+.ui-button,.ui-dialog .ui-button+.ui-datepicker-current,.ui-dialog .ui-button+.ui-datepicker-close,.ui-datepicker-current+.ibo-button,.ui-dialog .ui-datepicker-current+.ui-button,.ui-datepicker-current+.ui-datepicker-current,.ui-datepicker-current+.ui-datepicker-close,.ui-datepicker-close+.ibo-button,.ui-dialog .ui-datepicker-close+.ui-button,.ui-datepicker-close+.ui-datepicker-current,.ui-datepicker-close+.ui-datepicker-close,.ui-dialog .ibo-button+.ui-button,.ibo-button+.ui-datepicker-current,.ibo-button+.ui-datepicker-close{margin-left:4px}.ibo-button-group+.ibo-button-group,.ibo-button+.ibo-button-group,.ui-dialog .ui-button+.ibo-button-group,.ui-datepicker-current+.ibo-button-group,.ui-datepicker-close+.ibo-button-group,.ibo-button-group+.ibo-button,.ui-dialog .ibo-button-group+.ui-button,.ibo-button-group+.ui-datepicker-current,.ibo-button-group+.ui-datepicker-close{margin-left:4px}.ibo-collapsible-section+.ibo-collapsible-section{margin-top:12px}.ibo-collapsible-section+.ibo-block:not(.ibo-collapsible-section){margin-top:16px}.ibo-caselog-list .ibo-collapsible-section{margin:0;min-width:22em}.ibo-caselog-list .ibo-collapsible-section .ibo-collapsible-section--body{color:#212934;padding:8px;background-color:rgba(248, 249, 250, 0.5)}.ibo-alert--body .ibo-collapsible-section .ibo-collapsible-section--body{color:#212934;padding:8px}.ibo-alert--body>*+.ibo-collapsible-section{margin-top:8px}.ibo-datatable+.ibo-block{margin-top:4px}.ibo-panel .ibo-panel--body .ibo-datatable{width:100%}.display_block+.display_block{margin-top:24px}.display_block+.ibo-block:not(.display_block){margin-top:16px}.ibo-field+.ibo-field:not(:empty){margin-top:16px}.form_field+.form_field{margin-top:16px}.ibo-fieldset+.ibo-field,fieldset+.ibo-field{margin-top:32px}.ibo-field+.ibo-fieldset:not(.ibo-column),.ibo-field+fieldset:not(.ibo-column){margin-top:32px}.ibo-fieldset+.ibo-fieldset:not(.ibo-column),fieldset+.ibo-fieldset:not(.ibo-column),.ibo-fieldset+fieldset:not(.ibo-column){margin-top:48px}.ibo-multi-column+.ibo-fieldset,.ibo-multi-column+fieldset{margin-top:48px}.ibo-form+.ibo-form{margin-top:24px}select+label,label+select,label>select,input+label,label+input,label>input{margin-left:8px}.ibo-datatable .attribute-set .attribute-set-item{display:inline;margin:0;padding:4px 6px;box-shadow:0 1px 2px rgba(0, 0, 0, 0.25), 0 1px 3px rgba(0, 0, 0, 0.12)}.ibo-datatable .attribute-set .attribute-set-item+.attribute-set-item{margin-left:0.5rem}.ibo-object-details.ibo-has-medallion-icon>.ibo-panel--body>.ibo-tab-container:not(.ibo-is-vertical)>.ibo-tab-container--tabs-list{padding-left:calc(32px + 96px + 32px - 24px)}.tippy-box[data-theme~="object-summary"]{background-color:rgba(255, 255, 255, 0);color:#212934}.tippy-box[data-theme~="object-summary"] .tippy-arrow{display:none}.ibo-panel+.ibo-panel{margin-top:24px}.ibo-panel+.ibo-block:not(.ibo-panel){margin-top:16px}#ibo-main-content{}#ibo-main-content .ibo-panel.ibo-has-sticky-header{margin-bottom:200px}#ibo-main-content .ibo-panel.ibo-has-sticky-header>.ibo-sticky-sentinel-top{top:-16px;height:16px}#ibo-main-content .ibo-panel.ibo-has-sticky-header>.ibo-panel--header.ibo-is-sticking,#ibo-main-content .ibo-panel.ibo-has-sticky-header>.ibo-is-sticking.ibo-object-summary--header{top:-16px}.ui-dialog-content{}.ui-dialog-content .ibo-panel.ibo-has-sticky-header{}.ui-dialog-content .ibo-panel.ibo-has-sticky-header>.ibo-sticky-sentinel-top{top:-16px;height:16px}.ui-dialog-content .ibo-panel.ibo-has-sticky-header>.ibo-panel--header.ibo-is-sticking,.ui-dialog-content .ibo-panel.ibo-has-sticky-header>.ibo-is-sticking.ibo-object-summary--header{top:-16px}.ibo-pill:not(:last-child){margin-right:16px}.ibo-dashboard--grid-row .ibo-dashlet-header-static{margin-top:12px}.ibo-dashboard--grid-row:first-child .ibo-dashlet:first-child .ibo-dashlet-header-static{margin-top:0}.ibo-details .ibo-prop--apply>span,.ibo-details .ibo-prop--cancel>span{display:unset}.ibo-details .ibo-prop--apply{display:table-column}.ibo-activity-panel--tab-entry-form .ibo-caselog-entry-form{padding-bottom:14px;border-bottom:1px solid #aebecd}.ibo-panel{}.ibo-panel>.ibo-panel--body>.ibo-tab-container{margin-top:-24px;margin-left:-16px;margin-right:-16px;margin-bottom:-24px}.ibo-panel>.ibo-panel--body>.ibo-tab-container>.ibo-tab-container--tab-container-list{height:100%;overflow-y:auto;flex-grow:1}.ibo-panel>.ibo-panel--body>.ibo-tab-container.ibo-is-vertical{display:flex;flex-direction:row}.ibo-panel>.ibo-panel--body>.ibo-tab-container.ibo-is-vertical>.ibo-tab-container--tabs-list{padding-top:48px;flex-direction:column;height:auto;padding-left:unset;margin-right:unset;min-width:calc(32px + 90px + 32px)}.ibo-panel>.ibo-panel--body>.ibo-tab-container.ibo-is-vertical>.ibo-tab-container--tabs-list>.ibo-tab-container--tab-header,.ibo-panel>.ibo-panel--body>.ibo-tab-container.ibo-is-vertical>.ibo-tab-container--tabs-list>.ibo-tab-container--extra-tabs-container{height:48px;width:100%;justify-content:left}.ibo-panel>.ibo-panel--body>.ibo-tab-container.ibo-is-vertical>.ibo-tab-container--tabs-list>.ibo-tab-container--tab-header>.ibo-tab-container--tab-toggler,.ibo-panel>.ibo-panel--body>.ibo-tab-container.ibo-is-vertical>.ibo-tab-container--tabs-list>.ibo-tab-container--extra-tabs-container>.ibo-tab-container--tab-toggler,.ibo-panel>.ibo-panel--body>.ibo-tab-container.ibo-is-vertical>.ibo-tab-container--tabs-list>.ibo-tab-container--tab-header>.ibo-tab-container--extra-tabs-list-toggler,.ibo-panel>.ibo-panel--body>.ibo-tab-container.ibo-is-vertical>.ibo-tab-container--tabs-list>.ibo-tab-container--extra-tabs-container>.ibo-tab-container--extra-tabs-list-toggler{width:100%;justify-content:left}.ibo-panel>.ibo-panel--body>.ibo-tab-container.ibo-is-vertical>.ibo-tab-container--tab-container{flex-grow:1;margin-left:unset}.ibo-panel.ibo-has-sticky-header>.ibo-panel--body>.ibo-tab-container>.ibo-tab-container--tabs-list.ibo-is-sticking{position:fixed;z-index:10}.ibo-panel.ibo-has-sticky-header>.ibo-panel--body>.ibo-tab-container:not(.ibo-is-vertical)>.ibo-tab-container--tabs-list.ibo-is-sticking{padding-left:0}.ibo-panel.ibo-has-sticky-header>.ibo-panel--body>.ibo-tab-container:not(.ibo-is-vertical)>.ibo-tab-container--tabs-list.ibo-is-sticking .ibo-tab-container--tab-toggler,.ibo-panel.ibo-has-sticky-header>.ibo-panel--body>.ibo-tab-container:not(.ibo-is-vertical)>.ibo-tab-container--tabs-list.ibo-is-sticking .ibo-tab-container--extra-tabs-list-toggler,.ibo-panel.ibo-has-sticky-header>.ibo-panel--body>.ibo-tab-container:not(.ibo-is-vertical)>.ibo-tab-container--tabs-list.ibo-is-sticking .ibo-tab-container--extra-tabs-list-toggler{font-size:1rem}.ibo-block-list--medallion{flex-direction:column;align-items:center}.ibo-block-list--medallion>.ibo-medallion-icon--image{margin:0 auto}.ibo-block-list--medallion>.ibo-medallion-icon--image~.ibo-medallion-icon--description{margin-top:12px}.ibo-block-list--medallion>.ibo-medallion-icon--description{flex-grow:1;text-align:center}.ibo-datatable .ibo-field-badge{margin:0;padding:0;color:unset;background-color:unset}.ibo-datatable .ibo-field-badge::before{content:"";display:inline-flex;margin-right:0.5rem;width:10px;height:10px;min-width:10px;min-height:10px;background-color:var(--ibo-main-color)}.ibo-datatable .ibo-field-badge .ibo-field-badge--decoration{display:none}.ibo-datatable .ibo-field-badge .ibo-field-badge--decoration+.ibo-field-badge--label{margin-left:unset}.ui-dialog .blockUI.blockOverlay{background-color:white}.ibo-datatable .blockUI.blockOverlay{background-color:white}.ibo-datatable .blockUI.blockMsg{font-size:2em}.ibo-svg-illustration--container>svg *[fill="#6c63ff"]{fill:#ea7d1e}.ibo-navigation-menu.ibo-is-active .ibo-navigation-menu--drawer{transform:translate3d(0, 0, 0)}.switch{position:relative;display:inline-block;width:36px;height:20px;vertical-align:baseline}.switch input{display:none}.slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#929fb1;transition:0.4s}.slider:before{position:absolute;content:"";height:15px;width:15px;left:3px;bottom:3px;background-color:#d5dde5;transition:0.4s}input:checked+.slider{background-color:#dd6c20}input:focus+.slider{box-shadow:0 0 1px #dd6c20}input:checked+.slider:before{transform:translateX(14.5px)}.slider.round{border-radius:20px}.slider.round:before{border-radius:7px}.ibo-is-html-content blockquote{color:#212934}.center{text-align:center}.hidden{display:none}@keyframes progress_bar_color_ongoing{from{background-color:#FBD38D}to{background-color:#FEEBC8}}@-webkit-keyframes bg-pan-left{0%{background-position:100% 50%}100%{background-position:0 50%}}@keyframes bg-pan-left{0%{background-position:100% 50%}100%{background-position:0 50%}}body{display:flex;flex-direction:column;background-color:#f8f9fa;color:#212934;margin:0;padding:0;font-size:10pt;font-family:Tahoma, Verdana, Arial, Helvetica, serif;overflow-y:auto}h1{color:#555555;font-size:16pt}h2{color:#212934;font-size:14pt;font-weight:normal}h3{color:#1C94C4;font-size:12pt;font-weight:bold}a{color:#1c94c4;text-decoration:none}a:hover{color:#EA7D1E}.itop-setup--message{margin-top:16px}.next{width:100%;text-align:right}.v-spacer{padding-top:1em}button{margin-top:1em;padding-left:1em;padding-right:1em}p.info{padding-left:50px;background:url(../images/info-mid.png) no-repeat left -5px;min-height:48px}p.ok{padding-left:50px;background:url(../images/clean-mid.png) no-repeat left -8px;min-height:48px}p.warning{padding-left:50px;background:url(../images/messagebox_warning-mid.png) no-repeat left -5px;min-height:48px}p.error{padding-left:50px;background:url(../images/stop-mid.png) no-repeat left -5px;min-height:48px}label{cursor:pointer}td.label{text-align:left}label.read-only{color:#666;cursor:text}td.input{text-align:left}table.formTable{border:0}.wizlabel,.wizinput{color:#000;font-size:10pt}.wizhelp{color:#333;font-size:8pt}#progress{border:none;width:210px;height:26px;line-height:26px;text-align:center;margin:5px;box-shadow:inset 0 2px 4px 0 rgba(0, 0, 0, 0.06) !important;border-radius:2px;background-color:#EDF2F7 !important}#progress .progress{color:#000000 !important;background-image:linear-gradient(270deg, #FBD38D 50%, #FEEBC8 55%, #FBD38D 80%) !important;animation:bg-pan-left 3s infinite both;background-size:600% 100%;border-radius:inherit}#progress .progress.progress-error{background-image:none !important;background-color:#F56565 !important;animation:none}h3.clickable{background:url(../images/plus.gif) no-repeat left;padding-left:16px;cursor:hand}h3.clickable.open{background:url(../images/minus.gif) no-repeat left;padding-left:16px;cursor:hand}.message{color:#1A202C;background-color:#F7FAFC;border-left:4px solid #4A5568;padding:10px;font-size:initial}.message>.message-title{font-weight:bold;margin-right:5px}.message.message-valid{color:#276749;background-color:#F0FFF4;border-color:#48BB78}.message.message-warning{color:#C05621;background-color:#FFFAF0;border-color:#ED8936}.message.message-error{color:#C53030;background-color:#FFF5F5;border-color:#E53E3E}*:not(.message)+.message{margin-top:6px}.text-valid{color:#276749}.text-warning{color:#C05621}.text-error{color:#C53030}fieldset{border:none;padding:0;margin:15px 0 0 0}fieldset>legend{margin-bottom:7px;padding-bottom:7px;width:100%;color:#3C3C3C;font-size:11pt;font-weight:bold;border-bottom:1px solid #D2D2D2}.module-selection-banner img{max-height:48px}.module-selection-body{overflow:auto;box-shadow:inset 0 2px 4px 0 rgba(0, 0, 0, 0.06) !important;background-color:#F7FAFC;padding:10px}.module-selection-body .wiz-choice:checked~.description #itop-ticket-mgmt-simple-ticket-enhanced-portal:not(:checked)~.description::after,.module-selection-body .wiz-choice:checked~.description #itop-ticket-mgmt-itil-enhanced-portal:not(:checked)~.description::after{content:"Legacy portal is no longer part of iTop, by leaving this option unchecked your portal users won't be able to access iTop anymore.";display:block;margin-top:0.5em;font-weight:bold;color:#e60000b8}.module-selection-body .wiz-choice:not(:checked)~label .setup-extension-tag.checked{display:none}.module-selection-body .wiz-choice:checked~label .setup-extension-tag.unchecked{display:none}body{font-size:1.17rem;font-family:"Raleway"}#ibo_setup_container{width:800px;margin-left:auto;margin-right:auto;height:100%;display:flex;flex-direction:column;padding:20px 0}#ibo_setup_container pre{white-space:pre-wrap}#ibo_setup_container .ibo-title h2{margin-bottom:15px}#ibo_setup_container .ibo-setup--header{background-color:#fff;padding:0 20px;border:3px solid #ccd4db;height:80px;border-bottom:none;border-radius:3px 3px 0 0}#ibo_setup_container .ibo-setup--header .ibo-title--icon{border:0;vertical-align:middle;margin-right:20px}#ibo_setup_container .ibo-setup--body{display:flex;flex-direction:column;background-color:#fff;padding:20px;border:3px solid #ccd4db;border-top:none;flex-grow:1;overflow:auto;border-radius:0 0 3px 3px}#ibo_setup_container .ibo-setup--body .ibo-setup--wizard{width:100%;display:flex;flex-direction:column;height:100%}#ibo_setup_container .ibo-setup--body .ibo-setup--wizard .ibo-setup--wizard--content{overflow:auto}#ibo_setup_container .ibo-setup--body .ibo-setup--wizard .ibo-setup--wizard--buttons-container{margin-top:auto}#ibo_setup_container .ibo-setup--body .ibo-setup--wizard .ibo-setup--wizard--buttons-container tr{display:flex;justify-content:flex-end}#ibo_setup_container .ibo-setup--body .ibo-setup--wizard .ibo-setup--wizard--buttons-container button{margin-left:8px}#ibo_setup_container .ibo-setup--body .itop-setup--message{margin-top:16px}#ibo_setup_container .ibo-setup--body .ibo-setup--button-bar{margin-top:16px}#ibo_setup_container .ibo-setup--body .ibo-setup--button-bar .ibo-setup--button-spacer{flex-grow:1}#ibo_setup_container .ibo-setup--body .ibo-setup--js-error{overflow:auto;max-height:100px;color:#9b2c2c;font-size:1rem}#ibo_setup_container .ibo-setup--body .ibo-setup--upgrade-info{margin-top:5px}#ibo_setup_container .ibo-setup--body .ibo-fieldset,#ibo_setup_container .ibo-setup--body fieldset{margin-top:12px}#ibo_setup_container .ibo-setup--body .ibo-fieldset~.ibo-fieldset,#ibo_setup_container .ibo-setup--body fieldset~.ibo-fieldset,#ibo_setup_container .ibo-setup--body .ibo-fieldset~fieldset,#ibo_setup_container .ibo-setup--body fieldset~fieldset{margin-top:12px}#ibo_setup_container .ibo-setup--body .ibo-field{margin-top:5px}#ibo_setup_container .ibo-setup--body .ibo-setup--small-field-label .ibo-field--label{width:15%}#ibo_setup_container .ibo-setup--body .ibo-field--comments{font-size:1rem;color:#6e7a8a;text-align:left;width:100%;padding-left:10px}#ibo_setup_container .ibo-setup--body .ibo-alert{padding:7px 20px}#ibo_setup_container .ibo-setup--body .ibo-setup--small-message{font-size:1rem;color:#6e7a8a}#ibo_setup_container .ibo-setup--body .ibo-collapsible-section{margin:10px 0 0 0}#ibo_setup_container .ibo-setup--body .ibo-collapsible-section.ibo-setup--small .ibo-collapsible-section--header .ibo-collapsible-section--title{font-size:1.17rem;font-weight:400;color:#6e7a8a}#ibo_setup_container .ibo-setup--body .ibo-collapsible-section .ibo-collapsible-section--body{max-height:400px;overflow:auto}#ibo_setup_container .ibo-setup--body .ibo-input,#ibo_setup_container .ibo-setup--body .ui-autocomplete-input,#ibo_setup_container .ibo-setup--body .ui-multiselect,#ibo_setup_container .ibo-setup--body .dataTables_length select,.dataTables_length #ibo_setup_container .ibo-setup--body select,#ibo_setup_container .ibo-setup--body .ui_tpicker_hour_slider>select,#ibo_setup_container .ibo-setup--body .ui_tpicker_minute_slider>select,#ibo_setup_container .ibo-setup--body .ui_tpicker_second_slider>select,#ibo_setup_container .ibo-setup--body select.ibo-input-select-placeholder,#ibo_setup_container .ibo-setup--body .ibo-datatableconfig--attributes-panel--per-page--input,#ibo_setup_container .ibo-setup--body .search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content input[type="text"],.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content #ibo_setup_container .ibo-setup--body input[type="text"],#ibo_setup_container .ibo-setup--body .search_form_handler .sf_filter .sff_input_wrapper input[type="text"],.search_form_handler .sf_filter .sff_input_wrapper #ibo_setup_container .ibo-setup--body input[type="text"]{width:auto;display:inline-block}#ibo_setup_container .ibo-setup--body table td{white-space:nowrap;line-height:2.5rem;padding-right:8px;padding-bottom:1rem}#ibo_setup_container .ibo-setup--body .setup-content-title,#ibo_setup_container .ibo-setup--body h2{margin-bottom:18px}.ibo-setup--button-bar{margin-top:16px}.ibo-setup--button-bar .ibo-setup--full-width{width:100%}.ibo-setup--button-bar .ibo-setup--full-width{width:100%}.ibo-setup-summary-title{font-size:1.17rem}#ibo-setup-licenses--components-list{background-color:#f2f2f2;padding:12px;box-shadow:inset 0px 2px 4px 1px rgba(0, 0, 0, 0.15)}.setup-prefix-toggler--input--container,.setup-tls--input--container,.setup-disk-location--input--container,.setup-backup--input--container{display:flex;line-height:2.5rem;margin:1rem 0}.setup-prefix-toggler--input--container input,.setup-tls--input--container input,.setup-disk-location--input--container input,.setup-backup--input--container input{margin:0 8px}.setup-disk-location--input--container input,.setup-backup--input--container input{flex-grow:1}.collapsable-options{margin-bottom:18px}.collapsable-options [data-role="setup-collapsable-options--toggler"]::before{margin-right:8px;cursor:pointer}.collapsable-options:not(.setup-is-opened) [data-role="setup-collapsable-options--toggler"]::before{content:""}.collapsable-options.setup-is-opened [data-role="setup-collapsable-options--toggler"]::before{content:""}.setup-input--hint--icon{color:#6e7a8a}.setup-invalid-field--icon{color:#c53030;margin-left:8px}.setup-accept-licenses{margin-top:18px}.module-selection-banner{display:flex}.module-selection-banner>img{margin-right:12px}.setup-end-placeholder{display:flex;flex-direction:row;align-items:center}.setup-end-placeholder>div{padding:0px 15px}.setup-end-placeholder a{display:flex;flex-direction:column;align-items:center}.setup-end-placeholder a svg{max-height:150px;margin-bottom:15px;width:auto}.setup-extension--icon{margin-right:5px;color:#2b6bb0;font-size:1.33rem}.setup-extension--missing .setup-extension--icon{color:#a00000}.setup-extension-tag{background-color:grey;border-radius:8px;padding-left:3px;padding-right:3px;margin-right:3px}.setup-extension-tag.installed{background-color:#9eff9e}.setup-extension-tag.notinstalled{background-color:#ed9eff}.setup-extension-tag.tobeinstalled{background-color:#9ef0ff}.setup-extension-tag.tobeuninstalled{background-color:#ff9e9e}.setup-extension-tag.notuninstallable{background-color:#ffc98c}.setup-extension-tag.removed{background-color:#969594}.setup--wizard-choice--label+.setup--wizard-choice--more-info{margin-left:0.5rem}#params_summary{overflow:auto}#params_summary div{width:100%;margin-top:0;padding-top:0.5em;padding-left:0}#params_summary div ul{margin-left:0;padding-left:40px}#params_summary div.closed ul{display:none}#params_summary div li{list-style:none;width:100%;margin-left:0;padding-left:0em}.title{padding-left:20px;font-weight:bold;cursor:pointer}#params_summary div.closed .title::before{margin-right:5px;content:""}#params_summary div:not(.closed) .title::before{margin-right:5px;content:""}#progress_content{height:200px;overflow:auto;text-align:center}#installation_progress{display:none}#fresh_content{border:0;min-height:300px;min-width:600px;display:none;margin-left:auto;margin-right:auto} \ No newline at end of file + var(--ck-table-border-none-helper-line-color)}:where(.ck.ck-editor__editable.ck-table-show-hidden-borders .ck-widget.table) :where(td, th):where([style*="border:none"], [style*="border:0"], [style*="border-style:none"], [style*="border-width:0"]){border:var(--ck-table-border-none-helper-line) !important}:where(.ck.ck-editor__editable.ck-table-show-hidden-borders .ck-widget.table) :where(table, td, th):where([style*="border-top-style:none"], [style*="border-top-width:0"]){border-top:var(--ck-table-border-none-helper-line) !important}:where(.ck.ck-editor__editable.ck-table-show-hidden-borders .ck-widget.table) :where(table, td, th):where([style*="border-right-style:none"], [style*="border-right-width:0"]){border-right:var(--ck-table-border-none-helper-line) !important}:where(.ck.ck-editor__editable.ck-table-show-hidden-borders .ck-widget.table) :where(table, td, th):where([style*="border-bottom-style:none"], [style*="border-bottom-width:0"]){border-bottom:var(--ck-table-border-none-helper-line) !important}:where(.ck.ck-editor__editable.ck-table-show-hidden-borders .ck-widget.table) :where(table, td, th):where([style*="border-left-style:none"], [style*="border-left-width:0"]){border-left:var(--ck-table-border-none-helper-line) !important}.ck.ck-table-cell-properties-form{width:320px}.ck.ck-table-cell-properties-form .ck-form__row.ck-table-cell-properties-form__padding-row{align-self:flex-end;width:25%;padding:0}.ck.ck-table-cell-properties-form .ck-form__row.ck-table-cell-properties-form__alignment-row .ck.ck-toolbar{margin-top:var(--ck-spacing-standard);background:none}.ck.ck-table-cell-properties-form .ck-form__row.ck-table-cell-properties-form__alignment-row .ck.ck-toolbar.ck-table-cell-properties-form__horizontal-alignment-toolbar{--ck-table-form-dimensions-input-width: calc(var(--ck-table-form-default-input-width) * 2 + var(--ck-spacing-large));width:var(--ck-table-form-dimensions-input-width);max-width:var(--ck-table-form-dimensions-input-width);min-width:var(--ck-table-form-dimensions-input-width);padding:0}.ck.ck-table-cell-properties-form .ck-form__row.ck-table-cell-properties-form__alignment-row .ck.ck-toolbar.ck-table-cell-properties-form__vertical-alignment-toolbar{flex-grow:1}.ck.ck-table-cell-properties-form .ck-form__row.ck-table-cell-properties-form__alignment-row .ck.ck-toolbar:first-of-type{flex-grow:0.57}.ck.ck-table-cell-properties-form .ck-form__row.ck-table-cell-properties-form__alignment-row .ck.ck-toolbar:last-of-type{flex-grow:0.43}.ck.ck-table-cell-properties-form .ck-form__row.ck-table-cell-properties-form__alignment-row .ck.ck-toolbar .ck-button{flex-grow:1}.ck.ck-table-cell-properties-form .ck-form__row.ck-table-cell-properties-form__alignment-row{flex-wrap:wrap}.ck.ck-table-cell-properties-form .ck-form__row.ck-table-form__border-row .ck-labeled-field-view>.ck-label{font-size:var(--ck-font-size-tiny);text-align:center}.ck.ck-table-cell-properties-form .ck-form__row.ck-table-form__border-row .ck-table-form__border-style,.ck.ck-table-cell-properties-form .ck-form__row.ck-table-form__border-row .ck-table-form__border-width{width:80px;min-width:80px;max-width:80px}.ck.ck-table-cell-properties-form .ck-form__row.ck-table-form__dimensions-row{--ck-table-form-dimensions-input-width: calc(var(--ck-table-form-default-input-width) * 2 + var(--ck-spacing-large));width:var(--ck-table-form-dimensions-input-width);max-width:var(--ck-table-form-dimensions-input-width);min-width:var(--ck-table-form-dimensions-input-width);padding:0}.ck.ck-table-cell-properties-form .ck-form__row.ck-table-form__dimensions-row .ck-table-form__dimensions-row__width,.ck.ck-table-cell-properties-form .ck-form__row.ck-table-form__dimensions-row .ck-table-form__dimensions-row__height{width:var(--ck-table-form-default-input-width);min-width:var(--ck-table-form-default-input-width);max-width:var(--ck-table-form-default-input-width);margin:0}.ck.ck-table-cell-properties-form .ck-form__row.ck-table-form__dimensions-row .ck-table-form__dimension-operator{width:0;height:var(--ck-ui-component-min-height);line-height:var(--ck-ui-component-min-height);margin:0 var(--ck-spacing-small);align-self:flex-end;display:inline-block;position:relative;left:-0.5ch;overflow:visible}.ck.ck-table-cell-properties-form .ck-form__row.ck-form__row.ck-table-form__action-row>.ck.ck-button{flex-grow:initial}.ck.ck-table-cell-properties-form .ck-form__row.ck-form__row.ck-table-form__action-row>.ck.ck-button .ck-button__label{color:currentColor}.ck.ck-table-cell-properties-form .ck-form__row.ck-table-form__cell-type-row{--ck-table-form-dimensions-input-width: calc(var(--ck-table-form-default-input-width) * 2 + var(--ck-spacing-large));width:var(--ck-table-form-dimensions-input-width);max-width:var(--ck-table-form-dimensions-input-width);min-width:var(--ck-table-form-dimensions-input-width);padding:0}:root{--ck-table-layout-widget-type-around-button-size: 16px;--ck-table-layout-widget-type-around-icon-width: 10px;--ck-table-layout-widget-type-around-icon-height: 8px;--ck-table-layout-widget-handler-icon-size: 10px;--ck-table-layout-default-border-color: #d4d4d4}.ck-content table.table.layout-table,.ibo-is-html-content table.table.layout-table,.ck-content figure.table.layout-table,.ibo-is-html-content figure.table.layout-table{margin-top:0;margin-bottom:0}.ck-content table.table.layout-table,.ibo-is-html-content table.table.layout-table,.ck-content figure.table.layout-table>table,.ibo-is-html-content figure.table.layout-table>table{border-spacing:0}.ck-editor__editable .table.layout-table>table{border-collapse:revert;width:100%;height:100%}.ck-editor__editable .table.layout-table>table:not([style*="border:"], [style*="border-top"], [style*="border-bottom"], [style*="border-left"], [style*="border-right"], [style*="border-width"], [style*="border-style"], [style*="border-color"]){border-width:0;border-color:#0000;outline:none}.ck-editor__editable .table.layout-table>table>tbody>tr>td{box-shadow:revert;padding:revert;text-indent:1px;border-color:var(--ck-table-layout-default-border-color);border-style:dashed;min-width:2em}.ck-editor__editable .table.layout-table>table>tbody>tr>td[style^="width:"],.ck-editor__editable .table.layout-table>table>tbody>tr>td[style*=" width:"],.ck-editor__editable .table.layout-table>table>tbody>tr>td[style*=";width:"]{min-width:auto}.ck-editor__editable .table.layout-table>table>tbody>tr>td:focus{background-color:#0000}.ck-editor__editable .table.layout-table>table>tbody>tr>td:not([style*="border:"], [style*="border-top"], [style*="border-bottom"], [style*="border-left"], [style*="border-right"], [style*="border-width"], [style*="border-style"], [style*="border-color"]){outline:var(--ck-table-layout-default-border-color) 1px dashed;outline-offset:-1px;border-width:0;border-color:#0000}.ck-editor__editable .table.layout-table>table>tbody>tr>td:not([style*="border:"], [style*="border-top"], [style*="border-bottom"], [style*="border-left"], [style*="border-right"], [style*="border-width"], [style*="border-style"], [style*="border-color"]):focus{outline:var(--ck-color-focus-border) 1px solid}.ck-editor__editable .table.layout-table>table>tbody>tr>td>.ck-table-bogus-paragraph{text-indent:0;width:calc(100% - 1px)}.ck-editor__editable .table.layout-table.ck-widget>.ck-widget__type-around{--ck-widget-type-around-button-size: var(--ck-table-layout-widget-type-around-button-size)}.ck-editor__editable .table.layout-table.ck-widget>.ck-widget__type-around>.ck-widget__type-around__button.ck-widget__type-around__button_before,.ck-editor__editable .table.layout-table.ck-widget>.ck-widget__type-around>.ck-widget__type-around__button.ck-widget__type-around__button_after{z-index:2;transform:translateY(0)}.ck-editor__editable .table.layout-table.ck-widget>.ck-widget__type-around>.ck-widget__type-around__button.ck-widget__type-around__button_before{margin-left:var(--ck-table-layout-widget-type-around-button-size);border-radius:0 0 100px 100px;left:min(10%, 30px)}.ck-editor__editable .table.layout-table.ck-widget>.ck-widget__type-around>.ck-widget__type-around__button.ck-widget__type-around__button_before:after{border-radius:0 0 100px 100px}.ck-editor__editable .table.layout-table.ck-widget>.ck-widget__type-around>.ck-widget__type-around__button.ck-widget__type-around__button_after{border-radius:100px 100px 0 0}.ck-editor__editable .table.layout-table.ck-widget>.ck-widget__type-around>.ck-widget__type-around__button.ck-widget__type-around__button_after:after{border-radius:100px 100px 0 0}.ck-editor__editable .table.layout-table.ck-widget>.ck-widget__type-around>.ck-widget__type-around__button svg{width:var(--ck-table-layout-widget-type-around-icon-width);height:var(--ck-table-layout-widget-type-around-icon-height)}.ck-editor__editable .table.layout-table.ck-widget.ck-widget_with-selection-handle>.ck-widget__selection-handle{--ck-widget-handler-icon-size: var(--ck-table-layout-widget-handler-icon-size);transform:translateY(calc(0px - var(--ck-widget-outline-thickness)));z-index:3}.ck-editor__editable .table.layout-table.ck-widget.ck-widget_type-around_show-fake-caret_before>.ck-widget__type-around>.ck-widget__type-around__fake-caret{top:0}.ck-editor__editable .table.layout-table.ck-widget.ck-widget_type-around_show-fake-caret_after>.ck-widget__type-around>.ck-widget__type-around__fake-caret{bottom:0}.ck-editor__editable .table.layout-table.ck-widget:hover{z-index:var(--ck-z-default)}.ck-editor__editable .table.layout-table.ck-widget:hover>.ck-widget__selection-handle{opacity:0.75;visibility:visible}.ck-editor__editable .table.layout-table.ck-widget:hover>.ck-widget__selection-handle:hover{opacity:1}.ck-editor__editable .table.layout-table.ck-widget:has(.ck-widget.table:hover)>.ck-widget__selection-handle{opacity:0;visibility:hidden}.ck-editor__editable .table.layout-table.ck-widget.ck-widget_selected{z-index:var(--ck-z-default)}.ck-editor__editable .table.layout-table{margin:0;display:table}.ck-editor__editable.ck-editor__editable_inline>.ck-widget.ck-widget_with-selection-handle.layout-table:first-child{margin-top:var(--ck-spacing-large)}.ck-editor__editable.ck-editor__editable_inline>.ck-widget.ck-widget_with-selection-handle.layout-table:last-child,.ck-editor__editable.ck-editor__editable_inline>.ck-widget.ck-widget_with-selection-handle.layout-table:nth-last-child(2):has(+ .ck-fake-selection-container){margin-bottom:var(--ck-spacing-large)}.ck.ck-form__row>:not(.ck-label)+*{margin-inline-start:var(--ck-spacing-large)}.ck.ck-form__row>.ck-label{width:100%;min-width:100%}.ck.ck-form__row.ck-table-form__action-row{margin-top:var(--ck-spacing-large);justify-content:flex-end}.ck.ck-form__row.ck-table-form__action-row .ck-button-save,.ck.ck-form__row.ck-table-form__action-row .ck-button-cancel{justify-content:center}:root{--ck-table-properties-error-arrow-size: 6px;--ck-table-properties-min-error-width: 150px}.ck.ck-table-form{--ck-table-form-default-input-width: 80px}.ck.ck-table-form .ck-form__row.ck-table-form__border-row .ck-labeled-field-view>.ck-label{font-size:var(--ck-font-size-tiny);text-align:center}.ck.ck-table-form .ck-form__row.ck-table-form__border-row .ck-table-form__border-style,.ck.ck-table-form .ck-form__row.ck-table-form__border-row .ck-table-form__border-width{width:var(--ck-table-form-default-input-width);min-width:var(--ck-table-form-default-input-width);max-width:var(--ck-table-form-default-input-width)}.ck.ck-table-form .ck-form__row.ck-table-form__dimensions-row{--ck-table-form-dimensions-input-width: calc(var(--ck-table-form-default-input-width) * 2 + var(--ck-spacing-large));width:var(--ck-table-form-dimensions-input-width);max-width:var(--ck-table-form-dimensions-input-width);min-width:var(--ck-table-form-dimensions-input-width);padding:0}.ck.ck-table-form .ck-form__row.ck-table-form__dimensions-row .ck-table-form__dimensions-row__width,.ck.ck-table-form .ck-form__row.ck-table-form__dimensions-row .ck-table-form__dimensions-row__height{width:var(--ck-table-form-default-input-width);min-width:var(--ck-table-form-default-input-width);max-width:var(--ck-table-form-default-input-width);margin:0}.ck.ck-table-form .ck-form__row.ck-table-form__dimensions-row .ck-table-form__dimension-operator{width:0;height:var(--ck-ui-component-min-height);line-height:var(--ck-ui-component-min-height);margin:0 var(--ck-spacing-small);align-self:flex-end;display:inline-block;position:relative;left:-0.5ch;overflow:visible}.ck.ck-table-form .ck-form__row.ck-table-form__border-row,.ck.ck-table-form .ck-form__row.ck-table-form__background-row,.ck.ck-table-form .ck-form__row.ck-table-form__cell-type-row{flex-wrap:wrap}.ck.ck-table-form .ck-form__row.ck-table-form__dimensions-row,.ck.ck-table-form .ck-form__row.ck-table-form__cell-type-row{flex-wrap:wrap;align-items:center}:is(.ck.ck-table-form .ck-form__row.ck-table-form__dimensions-row, .ck.ck-table-form .ck-form__row.ck-table-form__cell-type-row) .ck-labeled-field-view{flex-direction:column-reverse;align-items:center;display:flex}:is(.ck.ck-table-form .ck-form__row.ck-table-form__dimensions-row, .ck.ck-table-form .ck-form__row.ck-table-form__cell-type-row) .ck-labeled-field-view .ck.ck-dropdown{flex-grow:0}.ck.ck-table-form .ck-form__row:not(.ck-table-form__action-row)>:not(.ck-label, .ck-table-form__dimension-operator){flex-grow:1}.ck.ck-table-form .ck.ck-labeled-field-view{padding-top:var(--ck-spacing-standard)}.ck.ck-table-form .ck.ck-labeled-field-view .ck.ck-labeled-field-view__status{border-radius:var(--ck-rounded-corners-radius);background:var(--ck-color-base-error);color:var(--ck-color-base-background);padding:var(--ck-spacing-small) var(--ck-spacing-medium);min-width:var(--ck-table-properties-min-error-width);text-align:center;left:50%;bottom:calc(-1 * var(--ck-table-properties-error-arrow-size));animation:0.15s both ck-table-form-labeled-view-status-appear;position:absolute;transform:translate(-50%, 100%)}.ck.ck-table-form .ck.ck-labeled-field-view .ck.ck-labeled-field-view__status:after{border-color:transparent transparent var(--ck-color-base-error) transparent;border-width:0 var(--ck-table-properties-error-arrow-size) var(--ck-table-properties-error-arrow-size) var(--ck-table-properties-error-arrow-size);content:"";top:calc(-1 * var(--ck-table-properties-error-arrow-size));border-style:solid;position:absolute;left:50%;transform:translateX(-50%)}@media (prefers-reduced-motion:reduce){.ck.ck-table-form .ck.ck-labeled-field-view .ck.ck-labeled-field-view__status{animation:none}}.ck.ck-table-form .ck.ck-labeled-field-view .ck.ck-labeled-field-view__status{z-index:1}.ck.ck-table-form .ck.ck-labeled-field-view .ck-input.ck-error:not(:focus)+.ck.ck-labeled-field-view__status{display:none}.ck.ck-table-form .ck.ck-labeled-field-view{position:relative}@keyframes ck-table-form-labeled-view-status-appear{0%{opacity:0}100%{opacity:1}}.ck.ck-table-properties-form{width:320px}.ck.ck-table-properties-form .ck-form__row.ck-table-properties-form__alignment-row{flex-wrap:wrap;flex-basis:0;align-content:baseline;align-self:flex-end}.ck.ck-table-properties-form .ck-form__row.ck-table-properties-form__alignment-row .ck.ck-toolbar{margin-top:var(--ck-spacing-standard);background:none}.ck.ck-table-properties-form .ck-form__row.ck-table-properties-form__alignment-row .ck.ck-toolbar .ck-toolbar__items>*{flex:1}.ck.ck-table-properties-form .ck-form__row.ck-table-properties-form__alignment-row .ck.ck-toolbar .ck-toolbar__items{flex-wrap:nowrap}:root{--ck-content-table-style-spacing: 1.5em}.ck-content .table.table-style-align-left,.ibo-is-html-content .table.table-style-align-left{float:left;margin-right:var(--ck-content-table-style-spacing)}.ck-content .table.table-style-align-right,.ibo-is-html-content .table.table-style-align-right{float:right;margin-left:var(--ck-content-table-style-spacing)}.ck-content .table.table-style-align-center,.ibo-is-html-content .table.table-style-align-center{margin-left:auto;margin-right:auto}.ck-content .table.table-style-block-align-left,.ibo-is-html-content .table.table-style-block-align-left{margin-left:0;margin-right:auto}.ck-content .table.table-style-block-align-right,.ibo-is-html-content .table.table-style-block-align-right{margin-left:auto;margin-right:0}.ck-editor__editable .table.layout-table.table-style-align-center{margin-left:auto;margin-right:auto}.ck-editor__editable .table.layout-table.table-style-align-left{margin-right:var(--ck-content-table-style-spacing)}.ck-editor__editable .table.layout-table.table-style-align-right{margin-left:var(--ck-content-table-style-spacing)}.ck-editor__editable .table.layout-table.table-style-block-align-left{margin-left:0;margin-right:auto}.ck-editor__editable .table.layout-table.table-style-block-align-right{margin-left:auto;margin-right:0}:root{--ck-content-color-table-caption-background: #f7f7f7;--ck-content-color-table-caption-text: #333;--ck-color-table-caption-highlighted-background: #fd0}.ck-content .table>figcaption,.ibo-is-html-content .table>figcaption,.ck-content figure.table>table>caption,.ibo-is-html-content figure.table>table>caption{caption-side:top;word-break:normal;overflow-wrap:anywhere;text-align:center;color:var(--ck-content-color-table-caption-text);background-color:var(--ck-content-color-table-caption-background);outline-offset:-1px;padding:0.6em;font-size:0.75em;display:table-caption}@media (forced-colors:active){.ck-content .table>figcaption,.ibo-is-html-content .table>figcaption,.ck-content figure.table>table>caption,.ibo-is-html-content figure.table>table>caption{background-color:unset;color:unset}}@media (forced-colors:none){:is(.ck.ck-editor__editable .table>figcaption, .ck.ck-editor__editable figure.table>table>caption).table__caption_highlighted{animation:0.6s ease-out ck-table-caption-highlight}}:is(.ck.ck-editor__editable .table>figcaption, .ck.ck-editor__editable figure.table>table>caption).ck-placeholder:before{padding-left:inherit;padding-right:inherit;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}@keyframes ck-table-caption-highlight{0%{background-color:var(--ck-color-table-caption-highlighted-background)}100%{background-color:var(--ck-content-color-table-caption-background)}}:root{--ck-table-selected-cell-background: #9ecffa4d}.ck.ck-editor__editable .table table td.ck-editor__editable_selected,.ck.ck-editor__editable .table table th.ck-editor__editable_selected{caret-color:#0000;box-shadow:unset;position:relative}:is(.ck.ck-editor__editable .table table td.ck-editor__editable_selected, .ck.ck-editor__editable .table table th.ck-editor__editable_selected):after{content:"";pointer-events:none;background-color:var(--ck-table-selected-cell-background);position:absolute;inset:0}:is(.ck.ck-editor__editable .table table td.ck-editor__editable_selected, .ck.ck-editor__editable .table table th.ck-editor__editable_selected) ::selection,:is(.ck.ck-editor__editable .table table td.ck-editor__editable_selected, .ck.ck-editor__editable .table table th.ck-editor__editable_selected):focus{background-color:#0000}:is(.ck.ck-editor__editable .table table td.ck-editor__editable_selected, .ck.ck-editor__editable .table table th.ck-editor__editable_selected) .ck-widget{outline:unset}:is(.ck.ck-editor__editable .table table td.ck-editor__editable_selected, .ck.ck-editor__editable .table table th.ck-editor__editable_selected) .ck-widget>.ck-widget__selection-handle{display:none}:root{--ck-color-table-column-resizer-hover: var(--ck-color-base-active);--ck-table-column-resizer-width: 7px;--ck-table-column-resizer-position-offset: calc(var(--ck-table-column-resizer-width) * -.5 - .5px)}.ck-content .table .ck-table-resized,.ibo-is-html-content .table .ck-table-resized{table-layout:fixed}.ck-content .table td,.ibo-is-html-content .table td,.ck-content .table th,.ibo-is-html-content .table th{overflow-wrap:break-word}.ck.ck-editor__editable .table td,.ck.ck-editor__editable .table th{position:relative}.ck.ck-editor__editable .table .ck-table-column-resizer{top:0;bottom:0;right:var(--ck-table-column-resizer-position-offset);width:var(--ck-table-column-resizer-width);cursor:col-resize;user-select:none;z-index:var(--ck-z-default);position:absolute}.ck.ck-editor__editable.ck-column-resize_disabled .table .ck-table-column-resizer,.ck.ck-editor__editable .table[draggable] .ck-table-column-resizer{display:none}.ck.ck-editor__editable .table .ck-table-column-resizer:hover,.ck.ck-editor__editable .table .ck-table-column-resizer__active{background-color:var(--ck-color-table-column-resizer-hover);opacity:0.25}.ck.ck-editor__editable[dir="rtl"] .table .ck-table-column-resizer{left:var(--ck-table-column-resizer-position-offset);right:unset}[dir="ltr"] :is(.ck.ck-input-color>.ck.ck-input-text){border-top-right-radius:0;border-bottom-right-radius:0}[dir="rtl"] :is(.ck.ck-input-color>.ck.ck-input-text){border-top-left-radius:0;border-bottom-left-radius:0}.ck.ck-input-color>.ck.ck-input-text:focus{z-index:0}.ck.ck-input-color>.ck.ck-dropdown>.ck.ck-button.ck-input-color__button{padding:0;display:flex}[dir="ltr"] :is(.ck.ck-input-color>.ck.ck-dropdown>.ck.ck-button.ck-input-color__button){border-top-left-radius:0;border-bottom-left-radius:0}[dir="ltr"] :is(.ck.ck-input-color>.ck.ck-dropdown>.ck.ck-button.ck-input-color__button):not(:focus){border-left:1px solid #0000}[dir="rtl"] :is(.ck.ck-input-color>.ck.ck-dropdown>.ck.ck-button.ck-input-color__button){border-top-right-radius:0;border-bottom-right-radius:0}[dir="rtl"] :is(.ck.ck-input-color>.ck.ck-dropdown>.ck.ck-button.ck-input-color__button):not(:focus){border-right:1px solid #0000}.ck.ck-input-color>.ck.ck-dropdown>.ck.ck-button.ck-input-color__button.ck-disabled{background:var(--ck-color-input-disabled-background)}.ck.ck-input-color>.ck.ck-dropdown>.ck.ck-button.ck-input-color__button>.ck.ck-input-color__button__preview{border-radius:var(--ck-rounded-corners-radius);border:1px solid var(--ck-color-input-border);width:20px;height:20px;position:relative;overflow:hidden}.ck.ck-input-color>.ck.ck-dropdown>.ck.ck-button.ck-input-color__button>.ck.ck-input-color__button__preview>.ck.ck-input-color__button__preview__no-color-indicator{transform-origin:50%;background:red;border-radius:2px;width:8%;height:150%;display:block;position:absolute;top:-30%;left:50%;transform:rotate(45deg)}.ck.ck-input-color .ck.ck-input-color__remove-color{width:100%;padding:calc(var(--ck-spacing-standard) / 2) var(--ck-spacing-standard);border-bottom-right-radius:0;border-bottom-left-radius:0}.ck.ck-input-color .ck.ck-input-color__remove-color:not(:focus){border-bottom:1px solid var(--ck-color-input-border)}[dir="ltr"] :is(.ck.ck-input-color .ck.ck-input-color__remove-color){border-top-right-radius:0}[dir="rtl"] :is(.ck.ck-input-color .ck.ck-input-color__remove-color){border-top-left-radius:0}.ck.ck-input-color .ck.ck-input-color__remove-color .ck.ck-icon{margin-right:var(--ck-spacing-standard)}[dir="rtl"] :is(.ck.ck-input-color .ck.ck-input-color__remove-color .ck.ck-icon){margin-right:0;margin-left:var(--ck-spacing-standard)}.ck.ck-input-color{flex-direction:row-reverse;width:100%;display:flex}.ck.ck-input-color>input.ck.ck-input-text{flex-grow:1;min-width:auto}.ck.ck-input-color>div.ck.ck-dropdown{min-width:auto}.ck.ck-input-color>div.ck.ck-dropdown>.ck-input-color__button .ck-dropdown__arrow{display:none}:root{--ck-insert-table-dropdown-padding: 10px;--ck-insert-table-dropdown-box-height: 11px;--ck-insert-table-dropdown-box-width: 12px;--ck-insert-table-dropdown-box-margin: 1px}.ck .ck-insert-table-dropdown__grid{width:calc(var(--ck-insert-table-dropdown-box-width) * 10 + var(--ck-insert-table-dropdown-box-margin) * 20 + var(--ck-insert-table-dropdown-padding) * 2);padding:var(--ck-insert-table-dropdown-padding) var(--ck-insert-table-dropdown-padding) 0;flex-flow:wrap;display:flex}.ck .ck-insert-table-dropdown__label,.ck[dir="rtl"] .ck-insert-table-dropdown__label{text-align:center}.ck .ck-insert-table-dropdown-grid-box{min-width:var(--ck-insert-table-dropdown-box-width);min-height:var(--ck-insert-table-dropdown-box-height);margin:var(--ck-insert-table-dropdown-box-margin);border:1px solid var(--ck-color-base-border);border-radius:1px;outline:none;transition:none}@media (prefers-reduced-motion:reduce){.ck .ck-insert-table-dropdown-grid-box{transition:none}}.ck .ck-insert-table-dropdown-grid-box:focus{box-shadow:none}.ck .ck-insert-table-dropdown-grid-box.ck-on{border-color:var(--ck-color-focus-border);background:var(--ck-color-focus-outer-shadow)}:root{--ck-widget-outline-thickness: 3px;--ck-widget-handler-icon-size: 16px;--ck-widget-handler-animation-duration: .2s;--ck-widget-handler-animation-curve: ease;--ck-color-widget-blurred-border: #dedede;--ck-color-widget-hover-border: #ffc83d;--ck-color-widget-editable-focus-background: var(--ck-color-base-background);--ck-color-widget-drag-handler-icon-color: var(--ck-color-base-background);--ck-color-resizer: var(--ck-color-focus-border);--ck-color-resizer-tooltip-background: #262626;--ck-color-resizer-tooltip-text: #f2f2f2;--ck-resizer-border-radius: var(--ck-border-radius);--ck-resizer-tooltip-offset: 10px;--ck-resizer-tooltip-height: calc(var(--ck-spacing-small) * 2 + 10px)}.ck .ck-widget{outline-width:var(--ck-widget-outline-thickness);transition:outline-color var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve);outline-style:solid;outline-color:#0000}@media (prefers-reduced-motion:reduce){.ck .ck-widget{transition:none}}.ck .ck-widget.ck-widget_selected,.ck .ck-widget.ck-widget_selected:hover{outline:var(--ck-widget-outline-thickness) solid var(--ck-color-focus-border)}.ck .ck-widget:hover{outline-color:var(--ck-color-widget-hover-border)}.ck .ck-widget{position:relative}.ck .ck-editor__nested-editable{border:1px solid #0000}.ck .ck-editor__nested-editable.ck-editor__nested-editable_focused,.ck .ck-editor__nested-editable:focus{box-shadow:var(--ck-inner-shadow), 0 0}@media (forced-colors:none){.ck .ck-editor__nested-editable.ck-editor__nested-editable_focused,.ck .ck-editor__nested-editable:focus{background-color:var(--ck-color-widget-editable-focus-background)}}:is(.ck .ck-editor__nested-editable.ck-editor__nested-editable_focused, .ck .ck-editor__nested-editable:focus):not(td, th){border:var(--ck-focus-ring);outline:none}.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle{box-sizing:border-box;opacity:0;transition:background-color var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve), visibility var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve), opacity var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve);border-radius:var(--ck-border-radius) var(--ck-border-radius) 0 0;left:calc(0px - var(--ck-widget-outline-thickness));background-color:#0000;padding:4px;top:0;transform:translateY(-100%)}@media (prefers-reduced-motion:reduce){.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle{transition:none}}.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle .ck-icon{width:var(--ck-widget-handler-icon-size);height:var(--ck-widget-handler-icon-size);color:var(--ck-color-widget-drag-handler-icon-color)}.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle .ck-icon .ck-icon__selected-indicator{opacity:0;transition:opacity 0.3s var(--ck-widget-handler-animation-curve)}@media (prefers-reduced-motion:reduce){.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle .ck-icon .ck-icon__selected-indicator{transition:none}}.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle .ck-icon{display:block}.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle:hover .ck-icon .ck-icon__selected-indicator{opacity:1}.ck .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle{position:absolute}.ck .ck-widget.ck-widget_with-selection-handle:hover>.ck-widget__selection-handle{opacity:1;background-color:var(--ck-color-widget-hover-border);visibility:visible}:is(.ck .ck-widget.ck-widget_with-selection-handle.ck-widget_selected, .ck .ck-widget.ck-widget_with-selection-handle.ck-widget_selected:hover)>.ck-widget__selection-handle{opacity:1;background-color:var(--ck-color-focus-border);visibility:visible}:is(.ck .ck-widget.ck-widget_with-selection-handle.ck-widget_selected, .ck .ck-widget.ck-widget_with-selection-handle.ck-widget_selected:hover)>.ck-widget__selection-handle .ck-icon .ck-icon__selected-indicator{opacity:1}.ck .ck-widget.ck-widget_with-selection-handle{position:relative}.ck[dir="rtl"] .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle{left:auto;right:calc(0px - var(--ck-widget-outline-thickness))}.ck.ck-editor__editable.ck-read-only .ck-widget{transition:none}.ck.ck-editor__editable.ck-read-only .ck-widget:not(.ck-widget_selected){--ck-widget-outline-thickness: 0px}.ck.ck-editor__editable.ck-read-only .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle,.ck.ck-editor__editable.ck-read-only .ck-widget.ck-widget_with-selection-handle .ck-widget__selection-handle:hover{background:var(--ck-color-widget-blurred-border)}.ck .ck-widget:has(.ck-widget.table:hover){outline-color:#0000}.ck .ck-widget.ck-widget_with-selection-handle:has(.ck-widget.table:hover)>.ck-widget__selection-handle{opacity:0;visibility:hidden}.ck.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected,.ck.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected:hover{outline-color:var(--ck-color-widget-blurred-border)}:is(.ck.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected, .ck.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected:hover).ck-widget_with-selection-handle>.ck-widget__selection-handle,:is(.ck.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected, .ck.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected:hover).ck-widget_with-selection-handle>.ck-widget__selection-handle:hover{background:var(--ck-color-widget-blurred-border)}.ck.ck-editor__editable:not(.ck-pagination-view)>.ck-widget.ck-widget_with-selection-handle:first-child,.ck.ck-editor__editable:not(.ck-pagination-view) blockquote>.ck-widget.ck-widget_with-selection-handle:first-child{margin-top:calc(1em + var(--ck-widget-handler-icon-size))}.ck .ck-size-view{background:var(--ck-color-resizer-tooltip-background);color:var(--ck-color-resizer-tooltip-text);border:1px solid var(--ck-color-resizer-tooltip-text);border-radius:var(--ck-resizer-border-radius);font-size:var(--ck-font-size-tiny);padding:0 var(--ck-spacing-small);height:var(--ck-resizer-tooltip-height);line-height:var(--ck-resizer-tooltip-height);display:block}.ck .ck-size-view.ck-orientation-top-left,.ck .ck-size-view.ck-orientation-top-right,.ck .ck-size-view.ck-orientation-bottom-right,.ck .ck-size-view.ck-orientation-bottom-left,.ck .ck-size-view.ck-orientation-above-center{position:absolute}.ck .ck-size-view.ck-orientation-top-left{top:var(--ck-resizer-tooltip-offset);left:var(--ck-resizer-tooltip-offset)}.ck .ck-size-view.ck-orientation-top-right{top:var(--ck-resizer-tooltip-offset);right:var(--ck-resizer-tooltip-offset)}.ck .ck-size-view.ck-orientation-bottom-right{bottom:var(--ck-resizer-tooltip-offset);right:var(--ck-resizer-tooltip-offset)}.ck .ck-size-view.ck-orientation-bottom-left{bottom:var(--ck-resizer-tooltip-offset);left:var(--ck-resizer-tooltip-offset)}.ck .ck-size-view.ck-orientation-above-center{top:calc(var(--ck-resizer-tooltip-height) * -1);left:50%;transform:translate(-50%)}:root{--ck-resizer-size: 10px;--ck-resizer-offset: calc(( var(--ck-resizer-size) / -2 ) - 2px);--ck-resizer-border-width: 1px}.ck .ck-widget__resizer{outline:1px solid var(--ck-color-resizer);pointer-events:none;display:none;position:absolute;top:0;left:0}.ck .ck-widget__resizer__handle{width:var(--ck-resizer-size);height:var(--ck-resizer-size);background:var(--ck-color-focus-border);border:var(--ck-resizer-border-width) solid #fff;border-radius:var(--ck-resizer-border-radius);pointer-events:all;position:absolute}.ck .ck-widget__resizer__handle.ck-widget__resizer__handle-top-left{top:var(--ck-resizer-offset);left:var(--ck-resizer-offset)}.ck .ck-widget__resizer__handle.ck-widget__resizer__handle-top-right{top:var(--ck-resizer-offset);right:var(--ck-resizer-offset)}.ck .ck-widget__resizer__handle.ck-widget__resizer__handle-bottom-right{bottom:var(--ck-resizer-offset);right:var(--ck-resizer-offset)}.ck .ck-widget__resizer__handle.ck-widget__resizer__handle-bottom-left{bottom:var(--ck-resizer-offset);left:var(--ck-resizer-offset)}.ck .ck-widget__resizer__handle.ck-widget__resizer__handle-top-left,.ck .ck-widget__resizer__handle.ck-widget__resizer__handle-bottom-right{cursor:nwse-resize}.ck .ck-widget__resizer__handle.ck-widget__resizer__handle-top-right,.ck .ck-widget__resizer__handle.ck-widget__resizer__handle-bottom-left{cursor:nesw-resize}.ck .ck-widget_with-resizer{position:relative}.ck-focused .ck-widget_with-resizer.ck-widget_selected>.ck-widget__resizer{display:block}:root{--ck-widget-type-around-button-size: 20px;--ck-color-widget-type-around-button-active: var(--ck-color-focus-border);--ck-color-widget-type-around-button-hover: var(--ck-color-widget-hover-border);--ck-color-widget-type-around-button-blurred-editable: var(--ck-color-widget-blurred-border);--ck-color-widget-type-around-button-radar-start-alpha: 0;--ck-color-widget-type-around-button-radar-end-alpha: .3;--ck-color-widget-type-around-button-icon: var(--ck-color-base-background)}.ck .ck-widget .ck-widget__type-around__button{width:var(--ck-widget-type-around-button-size);height:var(--ck-widget-type-around-button-size);background:var(--ck-color-widget-type-around-button);transition:opacity var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve), background var(--ck-widget-handler-animation-duration) var(--ck-widget-handler-animation-curve);opacity:0;pointer-events:none;z-index:var(--ck-z-default);border-radius:100px;display:block;position:absolute;overflow:hidden}@media (prefers-reduced-motion:reduce){.ck .ck-widget .ck-widget__type-around__button{transition:none}}.ck .ck-widget .ck-widget__type-around__button svg{width:10px;height:8px;margin-top:1px;transition:transform 0.5s;position:absolute;top:50%;left:50%;transform:translate(-50%, -50%)}@media (prefers-reduced-motion:reduce){.ck .ck-widget .ck-widget__type-around__button svg{transition:none}}.ck .ck-widget .ck-widget__type-around__button svg *{stroke-dasharray:10;stroke-dashoffset:0;fill:none;stroke:var(--ck-color-widget-type-around-button-icon);stroke-width:1.5px;stroke-linecap:round;stroke-linejoin:round}.ck .ck-widget .ck-widget__type-around__button svg line{stroke-dasharray:7}.ck .ck-widget .ck-widget__type-around__button svg{z-index:calc(var(--ck-z-default) + 2)}.ck .ck-widget .ck-widget__type-around__button:hover{animation:1s infinite ck-widget-type-around-button-sonar}.ck .ck-widget .ck-widget__type-around__button:hover svg polyline{animation:2s linear ck-widget-type-around-arrow-dash}.ck .ck-widget .ck-widget__type-around__button:hover svg line{animation:2s linear ck-widget-type-around-arrow-tip-dash}@media (prefers-reduced-motion:reduce){.ck .ck-widget .ck-widget__type-around__button:hover{animation:none}.ck .ck-widget .ck-widget__type-around__button:hover svg polyline,.ck .ck-widget .ck-widget__type-around__button:hover svg line{animation:none}}.ck .ck-widget .ck-widget__type-around__button.ck-widget__type-around__button_before{top:calc(-.5 * var(--ck-widget-outline-thickness));left:min(10%, 30px);transform:translateY(-50%)}.ck .ck-widget .ck-widget__type-around__button.ck-widget__type-around__button_after{bottom:calc(-.5 * var(--ck-widget-outline-thickness));right:min(10%, 30px);transform:translateY(50%)}.ck .ck-widget:hover>.ck-widget__type-around>.ck-widget__type-around__button{opacity:1;pointer-events:auto}.ck .ck-widget:not(.ck-widget_selected)>.ck-widget__type-around>.ck-widget__type-around__button{background:var(--ck-color-widget-type-around-button-hover)}.ck .ck-widget.ck-widget_selected>.ck-widget__type-around>.ck-widget__type-around__button,.ck .ck-widget>.ck-widget__type-around>.ck-widget__type-around__button:hover{background:var(--ck-color-widget-type-around-button-active)}:is(.ck .ck-widget.ck-widget_selected>.ck-widget__type-around>.ck-widget__type-around__button, .ck .ck-widget>.ck-widget__type-around>.ck-widget__type-around__button:hover):after{width:calc(var(--ck-widget-type-around-button-size) - 2px);height:calc(var(--ck-widget-type-around-button-size) - 2px);content:"";z-index:calc(var(--ck-z-default) + 1);background:linear-gradient(135deg, #fff0 0%, #ffffff4d 100%);border-radius:100px;display:block;position:absolute;top:1px;left:1px}.ck .ck-widget.ck-widget_selected.ck-widget_type-around_show-fake-caret_before,.ck .ck-widget.ck-widget_selected.ck-widget_type-around_show-fake-caret_after{outline-color:#0000}.ck .ck-widget.ck-widget_selected>.ck-widget__type-around>.ck-widget__type-around__button{opacity:1;pointer-events:auto}.ck .ck-widget.ck-widget_with-selection-handle>.ck-widget__type-around>.ck-widget__type-around__button_before{margin-left:20px}.ck .ck-widget .ck-widget__type-around__fake-caret{pointer-events:none;background:var(--ck-color-base-text);outline:1px solid #ffffff80;height:1px;animation:1s linear infinite forwards ck-widget-type-around-fake-caret-pulse}:is(.ck .ck-widget.ck-widget_type-around_show-fake-caret_before, .ck .ck-widget.ck-widget_type-around_show-fake-caret_after).ck-widget_selected:hover{outline-color:var(--ck-color-widget-hover-border)}:is(.ck .ck-widget.ck-widget_type-around_show-fake-caret_before, .ck .ck-widget.ck-widget_type-around_show-fake-caret_after)>.ck-widget__type-around>.ck-widget__type-around__button{opacity:0;pointer-events:none}:is(:is(.ck .ck-widget.ck-widget_type-around_show-fake-caret_before, .ck .ck-widget.ck-widget_type-around_show-fake-caret_after).ck-widget_with-selection-handle.ck-widget_selected, :is(.ck .ck-widget.ck-widget_type-around_show-fake-caret_before, .ck .ck-widget.ck-widget_type-around_show-fake-caret_after).ck-widget_with-selection-handle.ck-widget_selected:hover)>.ck-widget__selection-handle{opacity:0}:is(.ck .ck-widget.ck-widget_type-around_show-fake-caret_before, .ck .ck-widget.ck-widget_type-around_show-fake-caret_after).ck-widget_selected.ck-widget_with-resizer>.ck-widget__resizer{opacity:0}.ck .ck-widget>.ck-widget__type-around>.ck-widget__type-around__fake-caret{display:none;position:absolute;left:0;right:0}.ck .ck-widget:hover>.ck-widget__type-around>.ck-widget__type-around__fake-caret{left:calc(-1 * var(--ck-widget-outline-thickness));right:calc(-1 * var(--ck-widget-outline-thickness))}.ck .ck-widget.ck-widget_type-around_show-fake-caret_before>.ck-widget__type-around>.ck-widget__type-around__fake-caret{top:calc(-1 * var(--ck-widget-outline-thickness) - 1px);display:block}.ck .ck-widget.ck-widget_type-around_show-fake-caret_after>.ck-widget__type-around>.ck-widget__type-around__fake-caret{bottom:calc(-1 * var(--ck-widget-outline-thickness) - 1px);display:block}.ck[dir="rtl"] .ck-widget.ck-widget_with-selection-handle .ck-widget__type-around>.ck-widget__type-around__button_before{margin-left:0;margin-right:20px}:is(.ck-editor__nested-editable.ck-editor__editable_selected .ck-widget.ck-widget_selected, .ck-editor__nested-editable.ck-editor__editable_selected .ck-widget:hover)>.ck-widget__type-around>.ck-widget__type-around__button{opacity:0;pointer-events:none}.ck .ck-widget:has(.ck-widget.table:hover)>.ck-widget__type-around>.ck-widget__type-around__button{opacity:0;pointer-events:none}.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected>.ck-widget__type-around>.ck-widget__type-around__button:not(:hover){background:var(--ck-color-widget-type-around-button-blurred-editable)}.ck-editor__editable.ck-blurred .ck-widget.ck-widget_selected>.ck-widget__type-around>.ck-widget__type-around__button:not(:hover) svg *{stroke:#999}@keyframes ck-widget-type-around-arrow-dash{0%{stroke-dashoffset:10px}20%,100%{stroke-dashoffset:0}}@keyframes ck-widget-type-around-arrow-tip-dash{0%,20%{stroke-dashoffset:7px}40%,100%{stroke-dashoffset:0}}@keyframes ck-widget-type-around-button-sonar{0%{box-shadow:0 0 0 0 hsla(var(--ck-color-focus-border-coordinates), var(--ck-color-widget-type-around-button-radar-start-alpha))}50%{box-shadow:0 0 0 5px hsla(var(--ck-color-focus-border-coordinates), var(--ck-color-widget-type-around-button-radar-end-alpha))}100%{box-shadow:0 0 0 5px hsla(var(--ck-color-focus-border-coordinates), var(--ck-color-widget-type-around-button-radar-start-alpha))}}@keyframes ck-widget-type-around-fake-caret-pulse{0%{opacity:1}49%{opacity:1}50%{opacity:0}99%{opacity:0}100%{opacity:1}}.ck.ck-editor__editable.ck-read-only .ck-widget__type-around,.ck.ck-editor__editable.ck-widget__type-around_disabled .ck-widget__type-around{display:none}.ck.ck-editor__editable.ck-restricted-editing_mode_restricted .ck-widget__type-around{display:none}.ck.ck-editor__editable.ck-restricted-editing_mode_restricted div.restricted-editing-exception .ck-widget__type-around{display:initial}:root{--ck-color-list-button-on-background: #EFF0EF;--ck-color-list-button-on-background-focus: #EFF0EF;--ck-color-list-button-hover-background: #EFF0EF;--ck-color-list-button-on-text: black;--ck-color-image-caption-background: transparent;--ck-spacing-small: 0.35rem;--ck-ui-component-min-height: 1rem;--ck-icon-size: 1.3rem;--ck-z-default: 9999;--ck-z-panel: calc( var(--ck-z-default) + 999 );--ck-z-dialog: calc( var(--ck-z-panel) + 9999 );--ck-text-tiny-font-size: 0.7rem;--ck-text-small-font-size: 0.85rem;--ck-text-big-font-size: 1.4rem;--ck-text-huge-font-size: 1.8rem;--ck-content-font-size: 1rem}.text-tiny{font-size:var(--ck-text-tiny-font-size)}.text-small{font-size:var(--ck-text-small-font-size)}.text-big{font-size:var(--ck-text-big-font-size)}.text-huge{font-size:var(--ck-text-huge-font-size)}.ck-editor{z-index:0}.ck-content .image img,.ibo-is-html-content .image img{min-width:inherit;margin-left:0;margin-right:0}.ck-content .image-style-align-left,.ibo-is-html-content .image-style-align-left,.ck-content .image-style-align-right,.ibo-is-html-content .image-style-align-right{display:block;float:unset}.ck-content .image-style-align-left,.ibo-is-html-content .image-style-align-left{text-align:left;margin-right:0}.ck-content .image-style-align-right,.ibo-is-html-content .image-style-align-right{text-align:right;margin-left:0}.ck-content figure,.ibo-is-html-content figure{margin-left:0;margin-right:0}.ck-content figure table,.ibo-is-html-content figure table{text-align:initial}.ck-content .table,.ibo-is-html-content .table{margin-left:0;margin-right:0}.ck-content .table table th,.ibo-is-html-content .table table th{background-color:#F4F4F4}.ck-content .marker-yellow,.ibo-is-html-content .marker-yellow{background-color:#FDFD77}.ck-content .marker-green,.ibo-is-html-content .marker-green{background-color:#62F962}.ck-content .marker-pink,.ibo-is-html-content .marker-pink{background-color:#FC7899}.ck-content .marker-blue,.ibo-is-html-content .marker-blue{background-color:#72CCFD}.ck.ck-fullscreen__main-wrapper .ck-fullscreen__sidebar{display:none}.ck-fullscreen__editable{display:flex;flex-direction:column;width:100%;margin:0;padding:0}.ck-table-show-hidden-borders{width:100%;max-width:100%;margin:0;border:0;padding:2em;flex-grow:1}.ck-fullscreen__main-wrapper .ck-fullscreen__editable-wrapper{--ck-fullscreen-editor-top-margin: 0;--ck-fullscreen-editor-bottom-margin: 0;flex-grow:1}.ck-fullscreen__main-wrapper .ck-fullscreen__editable::after{display:none}.ck.ck-fullscreen__right-edge{margin-left:0}.ck-fullscreen__main-wrapper .ck-fullscreen__editable .ck.ck-editor__editable:not(.ck-editor__nested-editable){height:100%;width:100%;max-width:100%;padding:0}:root{--ck-content-font-family: inherit;--ck-content-font-color: inherit;--ck-content-font-size: inherit;--ck-content-line-height: inherit;--ck-content-word-break: inherit;--ck-content-overflow-wrap: inherit}.ck{--ck-color-list-button-on-background: #e1e7ec;--ck-color-list-button-on-background-focus: #e1e7ec;--ck-color-list-button-hover-background: #e1e7ec;--ck-color-list-button-on-text: #212934;--ck-text-tiny-font-size: 0.67rem;--ck-text-small-font-size: 0.83rem;--ck-text-big-font-size: 1.33rem;--ck-text-huge-font-size: 1.83rem;--ck-color-image-caption-text: #212934}.ck-editor{width:100% !important;display:inline-grid;z-index:1}.ck-editor .ck-editor__main{overflow:auto}.ck.ck-content,.ck.ibo-is-html-content{color:#212934}.ck.ck-content .table table,.ck.ibo-is-html-content .table table{width:100% !important}.ck-editor__editable_inline:not(.ck-comment__input *){height:200px}.ck-content pre[data-language],.ibo-is-html-content pre[data-language]{padding:0 !important}.ck-content pre[data-language] code,.ibo-is-html-content pre[data-language] code{display:block;background:#212934 !important;padding:0.9rem !important;color:white !important}.ck-maximize_editor_main .ck-source-editing-area textarea{overflow:auto !important}.ck-mentions .ck-button{line-height:1.6rem;padding:4px 8px !important}.c3 path:not(.c3-legend-item-tile),.c3 line:not(.c3-legend-item-tile){stroke:#212934 !important}.c3-chart-arc path:not(.c3-legend-item-tile){stroke:white !important}.c3-axis{fill:#212934 !important}.c3-tooltip th{background-color:#aebecd !important;color:white !important}.c3-tooltip td{background-color:#929fb1 !important}.c3-legend-background{fill:white !important;stroke:#f2f2f2 !important}.c3-tooltip{background-color:#aebecd !important}.c3-tooltip tr{border:1px solid #CCC}.c3-legend-item{fill:#212934 !important}.tippy-content{white-space:pre-line}.ui-dialog{box-sizing:content-box;display:flex;flex-direction:column;position:absolute;top:0;left:0;background-color:white;border-radius:5px;overflow:hidden;outline:0;z-index:21}.ui-dialog .ui-dialog-titlebar{padding:0.4em 30px;position:relative;background-color:white;height:50px;border-bottom:solid 1px #e1e7ec;display:flex;flex-direction:row;align-items:center;justify-content:space-between}.ui-dialog .ui-dialog-title{float:left;margin:0.1em 0;width:100%;padding-right:24px}.ui-dialog .ui-dialog-titlebar-close{position:absolute;right:0;top:0.4em;width:20px;margin:-10px 0 0 0;padding:1px;height:20px}.ui-dialog .ui-dialog-content{box-sizing:content-box;position:relative;padding:16px 30px;overflow:auto}.ui-dialog .ui-dialog-buttonpane{margin-top:auto;text-align:left;border-width:1px 0 0 0;background-image:none;padding:0.4em 30px;position:relative;background-color:white;border-top:solid 1px #e1e7ec;height:50px}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right}.ui-dialog .ui-dialog-buttonpane button{margin:0.5em 0.4em 0.5em 0;cursor:pointer}.ui-dialog .ui-resizable-n{height:2px;top:0}.ui-dialog .ui-resizable-e{width:2px;right:0}.ui-dialog .ui-resizable-s{height:2px;bottom:0}.ui-dialog .ui-resizable-w{width:2px;left:0}.ui-dialog .ui-resizable-se{width:7px;height:7px;right:0;bottom:0}.ui-dialog .ui-resizable-sw{width:7px;height:7px;left:0;bottom:0}.ui-dialog .ui-resizable-ne{width:7px;height:7px;right:0;top:0}.ui-dialog .ui-resizable-nw{width:7px;height:7px;left:0;top:0}.ui-dialog .ui-button>.ui-icon{background-image:none;float:unset;margin:auto}.ui-dialog .ui-button>.ui-icon.ui-icon-closethick::after{content:"";font-family:"Font Awesome 5 Free";font-weight:600;text-indent:0;position:absolute;left:0px;width:100%;top:4px}.ui-button-icon-only{text-indent:-9999px;white-space:nowrap}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-widget-overlay.ui-front{position:fixed;top:0;left:0;width:100%;height:100%;opacity:0.6;filter:alpha(opacity=60);background-color:#37474f}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:0.1px;display:block;-ms-touch-action:none;touch-action:none}.ui-resizable-disabled .ui-resizable-handle{display:none}.ui-resizable-autohide .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.ui-layout-pane{overflow:auto}.ui-datepicker{display:none;background-color:white;border-radius:5px;box-shadow:0 1px 2px rgba(0, 0, 0, 0.25), 0 1px 3px rgba(0, 0, 0, 0.12);z-index:32 !important;padding:0 8px 5px 8px}.ui-datepicker .ui-datepicker-header{position:relative;margin:8px 8px 4px 8px;padding-top:24px}.ui-datepicker .ui-datepicker-prev,.ui-datepicker .ui-datepicker-next{position:absolute;top:0}.ui-datepicker .ui-datepicker-prev{left:0}.ui-datepicker .ui-datepicker-next{right:0}.ui-datepicker .ui-datepicker-title{display:flex;justify-content:space-evenly}.ui-datepicker .ui-datepicker-title select{flex-grow:1}.ui-datepicker .ui-datepicker-year{margin-left:8px}.ui-datepicker .ui-datepicker-calendar{margin:0 8px 8px 8px}.ui-datepicker th{padding:0.7em 0.3em;text-align:center;font-weight:bold}.ui-datepicker td{padding:1px}.ui-datepicker td span,.ui-datepicker td a{display:block;padding:0.2em 0;text-align:center;width:23px;border-radius:100%;color:#c05621}.ui-datepicker td span.ui-state-active,.ui-datepicker td a.ui-state-active{background-color:#c05621;color:floralwhite}.ui-datepicker td span.ui-state-highlight:not(.ui-state-active),.ui-datepicker td a.ui-state-highlight:not(.ui-state-active){background-color:#feebc8}.ui-datepicker td span.ui-state-hover:not(.ui-state-active),.ui-datepicker td a.ui-state-hover:not(.ui-state-active){color:#7b341e}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:0.7em 0 0 0;padding:0 0.2em;border-left:0;border-right:0;border-bottom:0}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:0.5em 0.2em 0.4em;cursor:pointer;padding:0.2em 0.6em 0.3em 0.6em;width:auto;overflow:visible}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto 0.4em}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-row-break{clear:both;width:100%;font-size:0}.ui-datepicker-rtl{direction:rtl}.ui-datepicker-rtl .ui-datepicker-prev{right:2px;left:auto}.ui-datepicker-rtl .ui-datepicker-prev:hover{right:1px;left:auto}.ui-datepicker-rtl .ui-datepicker-next{left:2px;right:auto}.ui-datepicker-rtl .ui-datepicker-next:hover{left:1px;right:auto}.ui-datepicker-rtl .ui-datepicker-buttonpane{clear:right}.ui-datepicker-rtl .ui-datepicker-buttonpane button{float:left}.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current{float:right}.ui-datepicker-rtl .ui-datepicker-group{float:right}.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-slider{position:relative;text-align:left;background-color:#f8f9fa;border:solid 1px #929fb1;border-radius:3px}.ui-slider .ui-slider-handle{background-color:white;border:solid 1px #929fb1;border-radius:3px;position:absolute;z-index:2;width:1.4em;height:1.4em;-ms-touch-action:none;touch-action:none;cursor:pointer}.ui-slider .ui-slider-handle:hover,.ui-slider .ui-slider-handle:active{border:solid 1px #c05621}.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:0.7em;display:block;background-position:0 0}.ui-slider.ui-state-disabled .ui-slider-handle{filter:inherit}.ui-slider.ui-state-disabled .ui-slider-range{filter:inherit}.ui-slider-horizontal{height:0.8em}.ui-slider-horizontal .ui-slider-handle{top:-0.2em;margin-left:-0.6em}.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:0.8em;height:100px}.ui-slider-vertical .ui-slider-handle{left:-0.3em;margin-left:0;margin-bottom:-0.6em}.ui-slider-vertical .ui-slider-range{left:0;width:100%}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default;z-index:100}.ui-autocomplete .ui-menu-item{padding:0}.ui-autocomplete-input{width:auto;display:inline}.ui-helper-hidden-accessible{clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-tabs-tab.ui-state-disabled a{cursor:not-allowed !important}.ui-multiselect{width:auto !important;padding-left:0.7em !important;padding-right:1.5em !important;text-align:left;white-space:nowrap;overflow:hidden;display:grid}button.ui-multiselect>span{overflow:hidden}.ui-multiselect span.ui-icon{float:right}.ui-multiselect-single .ui-multiselect-checkboxes input{position:absolute !important;top:auto !important;left:-9999px}.ui-multiselect-single .ui-multiselect-checkboxes label{padding:5px !important}.ui-multiselect-header{margin-bottom:3px;padding:3px 0}.ui-multiselect-header ul{padding-left:24px}.ui-multiselect-header ul li{float:left;padding:0 10px 0 0}.ui-multiselect-header span.ui-icon{float:left}.ui-multiselect-header li.ui-multiselect-close{float:right;text-align:right;padding-right:0}.ui-multiselect-menu{display:none;padding:3px;position:absolute;z-index:10000;text-align:left}.ui-multiselect-checkboxes{position:relative;overflow-y:scroll !important}.ui-multiselect-checkboxes label{display:flex;align-items:center;cursor:pointer;padding:3px 1px}.ui-multiselect-checkboxes label input{margin-right:5px;position:relative;top:1px}.ui-multiselect-checkboxes li{clear:both;padding-right:3px}.ui-multiselect-checkboxes li.ui-multiselect-optgroup-label{text-align:center}.ui-multiselect-checkboxes li.ui-multiselect-optgroup-label a{display:block;padding:3px;margin:1px 0;text-decoration:none}.ui-dialog-titlebar.ui-multiselect-header{padding-left:20px;padding-right:20px}.ui-dialog-titlebar.ui-multiselect-header ul{padding-left:0;width:100%}.ui-dialog-titlebar.ui-multiselect-header a{color:#212934;font-weight:normal}.ui-multiselect,.ui-multiselect-menu,.ui-multiselect-header{background-color:#f8f9fa}button.ui-multiselect{padding-right:10px !important}button.ui-multiselect .fas{float:right;padding-left:10px}.dataTables_paginate{color:#404b5a}.dataTables_paginate a.paginate_button{display:inline-flex;justify-content:center;align-items:center;padding:0 5px;min-width:20px;height:20px;border-radius:3px}.dataTables_paginate a.paginate_button:hover{background-color:#f8f9fa}.dataTables_paginate a.paginate_button.disabled{color:#929fb1;background-color:transparent;cursor:default}.dataTables_paginate a.paginate_button.current{color:#212934;background-color:#e1e7ec;box-shadow:inset 0px 1px 0px rgba(0, 0, 0, 0.15)}.dataTables_length select{}.dataTables_length select[aria-controls]{display:inline-flex;width:unset;min-width:50px;height:20px;padding:0 4px}.dataTables_scrollHead{}.dataTables_scrollHead thead tr th{cursor:pointer}.dataTables_scrollHead thead tr th.sorting::after{position:absolute;right:calc((12px - 8px) / 2);content:"";opacity:0.3;line-height:inherit}.dataTables_scrollHead thead tr th.sorting_asc:after{content:"";opacity:1}.dataTables_scrollHead thead tr th.sorting_desc:after{content:"";opacity:1}.dataTables_scrollHeadInner{border-bottom:1px solid #ccd4db}.dataTable th,.dataTable td{position:relative;padding:10px 12px}.dataTable tr:nth-child(odd){background-color:white}.dataTable tr:nth-child(even){background-color:#f2f2f2}.dataTable tr.ibo-is-red{background-color:#fce8e8}.dataTable tr.ibo-is-danger{background-color:#fed7d7}.dataTable tr.ibo-is-alert{background-color:#fed7d7}.dataTable tr.ibo-is-orange{background-color:floralwhite}.dataTable tr.ibo-is-warning{background-color:#feebc8}.dataTable tr.ibo-is-blue{background-color:#bee3f8}.dataTable tr.ibo-is-info{background-color:#bee3f8}.dataTable tr.ibo-is-green{background-color:#dcedc8}.dataTable tr.ibo-is-success{background-color:#c5e1a5}.dataTable tr.ibo-is-red td:first-child::before{content:"";position:absolute;left:0;top:0;width:3px;height:100%;background-color:#feb2b2}.dataTable tr.ibo-is-danger td:first-child::before{content:"";position:absolute;left:0;top:0;width:3px;height:100%;background-color:#fc8181}.dataTable tr.ibo-is-alert td:first-child::before{content:"";position:absolute;left:0;top:0;width:3px;height:100%;background-color:#fc8181}.dataTable tr.ibo-is-orange td:first-child::before{content:"";position:absolute;left:0;top:0;width:3px;height:100%;background-color:#fbd38d}.dataTable tr.ibo-is-warning td:first-child::before{content:"";position:absolute;left:0;top:0;width:3px;height:100%;background-color:#f6ae55}.dataTable tr.ibo-is-blue td:first-child::before{content:"";position:absolute;left:0;top:0;width:3px;height:100%;background-color:#63b4ed}.dataTable tr.ibo-is-info td:first-child::before{content:"";position:absolute;left:0;top:0;width:3px;height:100%;background-color:#63b4ed}.dataTable tr.ibo-is-green td:first-child::before{content:"";position:absolute;left:0;top:0;width:3px;height:100%;background-color:#aed581}.dataTable tr.ibo-is-success td:first-child::before{content:"";position:absolute;left:0;top:0;width:3px;height:100%;background-color:#aed581}.treeview,.treeview ul{padding:0;margin:0;list-style:none}.treeview div.hitarea{height:15px;width:15px;margin-left:-15px;float:left;cursor:pointer}.treeview li{margin:0;padding:3px 0 3px 16px}.treeview a.selected{background-color:#f8f9fa}#treecontrol{margin:1em 0}.treeview .hover{color:#dd6c20;cursor:pointer}.treeview li{background:url("..//images/tv-item.gif") 0 0 no-repeat}.treeview .collapsable{background-image:url("..//images/tv-collapsable.gif")}.treeview .expandable{background-image:url("..//images/tv-expandable.gif")}.treeview .last{background-image:url("..//images/tv-item-last.gif")}.treeview .lastCollapsable{background-image:url("..//images/tv-collapsable-last.gif")}.treeview .lastExpandable{background-image:url("..//images/tv-expandable-last.gif")}.filetree li{padding:3px 0 1px 16px}.filetree span.folder,.filetree span.file{padding-left:16px;display:block;height:15px}.filetree span.folder{background:url("..//images/tv-folder.gif") 0 0 no-repeat}.filetree span.file{background:url("..//images/tv-file.gif") 0 0 no-repeat}.blockUI.blockOverlay{background-color:#f2f2f2}.blockUI.blockMsg{font-size:6em;text-align:center;color:#6e7a8a;border:none;background-color:transparent}.mfp-bg{z-index:1100}.mfp-wrap{z-index:1101}.selectize-dropdown,.selectize-input,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active,.selectize-input input,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active input{color:#212934}.selectize-control.single .selectize-input,.selectize-control.single .ibo-quick-create--input.selectize-control.single .selectize-input.input-active,.ibo-quick-create--input.selectize-control.single .selectize-control.single .selectize-input.input-active{box-shadow:unset;background-color:white;background-image:unset;background-repeat:unset}.selectize-input,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active,.selectize-control.single .selectize-input.input-active,.selectize-control.single .ibo-quick-create--input.selectize-control.single .selectize-input.input-active,.ibo-quick-create--input.selectize-control.single .selectize-control.single .selectize-input.input-active{background:unset;background-color:white;cursor:text;display:inline-flex}.selectize-control.single .selectize-input.dropdown-active:after,.selectize-control.single .ibo-quick-create--input.selectize-control.single .dropdown-active.selectize-input.input-active:after,.ibo-quick-create--input.selectize-control.single .selectize-control.single .dropdown-active.selectize-input.input-active:after{margin-top:unset;border-width:unset;border-color:unset}.selectize-control.single .selectize-input:after,.selectize-control.single .ibo-quick-create--input.selectize-control.single .selectize-input.input-active:after,.ibo-quick-create--input.selectize-control.single .selectize-control.single .selectize-input.input-active:after,.selectize-control.single .selectize-input:not(.no-arrow):after,.selectize-control.single .ibo-quick-create--input.selectize-control.single .selectize-input.input-active:not(.no-arrow):after,.ibo-quick-create--input.selectize-control.single .selectize-control.single .selectize-input.input-active:not(.no-arrow):after{content:unset}.selectize-input::after,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active::after{content:unset}.selectize-input>*,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active>*{display:inline-flex}.selectize-control.single .selectize-input,.selectize-control.single .ibo-quick-create--input.selectize-control.single .selectize-input.input-active,.ibo-quick-create--input.selectize-control.single .selectize-control.single .selectize-input.input-active,.selectize-dropdown.single{border-color:#aebecd}.selectize-dropdown{background-color:white;color:#212934}.selectize-dropdown .selected,.selectize-dropdown .active,.selectize-dropdown .active:not(.selected){background:#ebf8ff;color:#212934}.selectize-dropdown [data-selectable],.selectize-dropdown .optgroup-header{padding:5px 8px}.selectize-dropdown .option{opacity:1}.selectize-add-option{display:inline-flex;justify-content:center;align-items:flex-end;position:absolute;right:0;padding-bottom:10px;height:100%;width:24px;z-index:1;color:#212934}.selectize-input .attribute-set-item>*,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active .attribute-set-item>*{display:inline}.selectize-input .attribute-set-item.item-add::before,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active .attribute-set-item.item-add::before,.selectize-input .attribute-set-item.item-remove::before,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active .attribute-set-item.item-remove::before{margin-right:4px}.selectize-input .attribute-set-item.item-add,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active .attribute-set-item.item-add{background-color:#dcedc8 !important}.selectize-input .attribute-set-item.item-add::before,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active .attribute-set-item.item-add::before{color:#33691e;content:""}.selectize-input .attribute-set-item.item-remove,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active .attribute-set-item.item-remove{background-color:#fce8e8 !important}.selectize-input .attribute-set-item.item-remove::before,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active .attribute-set-item.item-remove::before{color:#9b2c2c;content:""}.selectize-input .attribute-set-item.item-ignore-partial,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active .attribute-set-item.item-ignore-partial{background-color:#e1e7ec !important}.selectize-input.selectize-input-error,.ibo-quick-create--input.selectize-control.single .selectize-input-error.selectize-input.input-active{border:1px solid #e53e3e}.toastify.on{opacity:1}.toast-close{background:transparent;border:0;color:inherit;cursor:pointer;font-family:inherit;padding:0;margin-left:8px}.toastify-right{right:16px}.toastify-left{left:16px}.toastify-top{top:-150px}.toastify-bottom{bottom:-150px}.toastify-rounded{border-radius:25px}.toastify-avatar{width:1.5em;height:1.5em;margin:-7px 5px;border-radius:2px}.toastify-center{margin-left:auto;margin-right:auto;left:0;right:0;max-width:fit-content;max-width:-moz-fit-content}@media only screen and (max-width:360px){.toastify-right,.toastify-left{margin-left:auto;margin-right:auto;left:0;right:0;max-width:fit-content}}:root{--ibo-scrollbar--scrollbar-width: 8px;--ibo-scrollbar--scrollbar-height: 8px;--ibo-scrollbar--scrollbar-track-background-color: rgba(255, 255, 255, 0);--ibo-scrollbar--scrollbar-track-border-radius: 5px;--ibo-scrollbar--scrollbar-thumb-background-color: #d5dde5;--ibo-scrollbar--scrollbar-thumb-border: none;--ibo-scrollbar--scrollbar-thumb-border-radius: 5px}*,*::before,*::after{box-sizing:border-box}*{scrollbar-width:thin;scrollbar-color:var(--ibo-scrollbar--scrollbar-thumb-background-color) var(--ibo-scrollbar--scrollbar-track-background-color)}*::-webkit-scrollbar{width:var(--ibo-scrollbar--scrollbar-width);height:var(--ibo-scrollbar--scrollbar-height)}*::-webkit-scrollbar-track{background-color:var(--ibo-scrollbar--scrollbar-track-background-color);border-radius:var(--ibo-scrollbar--scrollbar-track-border-radius)}* ::-webkit-scrollbar-thumb{background-color:var(--ibo-scrollbar--scrollbar-thumb-background-color);border:var(--ibo-scrollbar--scrollbar-thumb-border);border-radius:var(--ibo-scrollbar--scrollbar-thumb-border-radius)}html{font-size:12px}a{color:var(--ibo-hyperlink-color);text-decoration:var(--ibo-hyperlink-text-decoration)}a:hover,a:active,a:visited{text-decoration:var(--ibo-hyperlink-text-decoration)}a:hover{color:var(--ibo-hyperlink-color--on-hover);text-decoration:var(--ibo-hyperlink-text-decoration--on-hover)}a:active{color:var(--ibo-hyperlink-color--on-active);text-decoration:var(--ibo-hyperlink-text-decoration--on-active)}.ibo-alert.ibo-is-primary{background-color:#feebc8;color:#7b341e}.ibo-alert.ibo-is-primary a{color:#7b341e}.ibo-alert.ibo-is-primary::before{background-color:#c05621}.ibo-alert.ibo-is-secondary,.ui-dialog .ibo-alert.ui-button,.ibo-alert.ui-datepicker-current,.ibo-alert.ui-datepicker-close{background-color:#e1e7ec;color:#212934}.ibo-alert.ibo-is-secondary a,.ui-dialog .ibo-alert.ui-button a,.ibo-alert.ui-datepicker-current a,.ibo-alert.ui-datepicker-close a{color:#212934}.ibo-alert.ibo-is-secondary::before,.ui-dialog .ibo-alert.ui-button::before,.ibo-alert.ui-datepicker-current::before,.ibo-alert.ui-datepicker-close::before{background-color:#6e7a8a}.ibo-alert.ibo-is-neutral,.ui-dialog .ibo-alert.ui-button.ui-dialog-titlebar-close{background-color:#e1e7ec;color:#212934}.ibo-alert.ibo-is-neutral a,.ui-dialog .ibo-alert.ui-button.ui-dialog-titlebar-close a{color:#212934}.ibo-alert.ibo-is-neutral::before,.ui-dialog .ibo-alert.ui-button.ui-dialog-titlebar-close::before{background-color:#6e7a8a}.ibo-toast.ibo-is-information,.ibo-alert.ibo-is-information{background-color:#bee3f8;color:#2a4265}.ibo-toast.ibo-is-information a,.ibo-alert.ibo-is-information a{color:#2a4265}.ibo-toast.ibo-is-information::before,.ibo-alert.ibo-is-information::before{background-color:#2b6bb0}.ibo-toast.ibo-is-success,.ibo-alert.ibo-is-success{background-color:#dcedc8;color:#33691e}.ibo-toast.ibo-is-success a,.ibo-alert.ibo-is-success a{color:#33691e}.ibo-toast.ibo-is-success::before,.ibo-alert.ibo-is-success::before{background-color:#689f38}.ibo-alert.ibo-is-failure{background-color:#fed7d7;color:#742a2a}.ibo-alert.ibo-is-failure a{color:#742a2a}.ibo-alert.ibo-is-failure::before{background-color:#c53030}.ibo-toast.ibo-is-warning,.ibo-alert.ibo-is-warning{background-color:#feebc8;color:#7b341e}.ibo-toast.ibo-is-warning a,.ibo-alert.ibo-is-warning a{color:#7b341e}.ibo-toast.ibo-is-warning::before,.ibo-alert.ibo-is-warning::before{background-color:#c05621}.ibo-toast.ibo-is-error,.ibo-alert.ibo-is-danger{background-color:#fed7d7;color:#742a2a}.ibo-toast.ibo-is-error a,.ibo-alert.ibo-is-danger a{color:#742a2a}.ibo-toast.ibo-is-error::before,.ibo-alert.ibo-is-danger::before{background-color:#c53030}.ibo-alert.ibo-is-grey{background-color:#e1e7ec;color:#212934}.ibo-alert.ibo-is-grey a{color:#212934}.ibo-alert.ibo-is-grey::before{background-color:#6e7a8a}.ibo-alert.ibo-is-blue-grey{background-color:#b0bec5;color:#263238}.ibo-alert.ibo-is-blue-grey a{color:#263238}.ibo-alert.ibo-is-blue-grey::before{background-color:#455a64}.ibo-alert.ibo-is-blue{background-color:#bee3f8;color:#2a4265}.ibo-alert.ibo-is-blue a{color:#2a4265}.ibo-alert.ibo-is-blue::before{background-color:#2b6bb0}.ibo-alert.ibo-is-cyan{background-color:#c9eef2;color:#006164}.ibo-alert.ibo-is-cyan a{color:#006164}.ibo-alert.ibo-is-cyan::before{background-color:#2b6bb0}.ibo-alert.ibo-is-green{background-color:#dcedc8;color:#33691e}.ibo-alert.ibo-is-green a{color:#33691e}.ibo-alert.ibo-is-green::before{background-color:#689f38}.ibo-alert.ibo-is-orange{background-color:#feebc8;color:#7b341e}.ibo-alert.ibo-is-orange a{color:#7b341e}.ibo-alert.ibo-is-orange::before{background-color:#c05621}.ibo-alert.ibo-is-red{background-color:#fed7d7;color:#742a2a}.ibo-alert.ibo-is-red a{color:#742a2a}.ibo-alert.ibo-is-red::before{background-color:#c53030}.ibo-alert.ibo-is-pink{background-color:#fed7e2;color:#702459}.ibo-alert.ibo-is-pink a{color:#702459}.ibo-alert.ibo-is-pink::before{background-color:#b83280}.ibo-alert{position:relative;padding:18px 20px;min-height:30px;border-radius:3px;overflow:hidden}.ibo-alert::before{display:block;position:absolute;top:0;left:0;content:"";width:4px;height:100%}.ibo-alert .ibo-alert--title{cursor:pointer}.ibo-alert.ibo-is-opened .ibo-alert--minimize-button,.ibo-alert.ibo-input-select-icon--menu .ibo-alert--minimize-button{display:block}.ibo-alert.ibo-is-opened .ibo-alert--maximize-button,.ibo-alert.ibo-input-select-icon--menu .ibo-alert--maximize-button{display:none}.ibo-alert:not(.ibo-is-opened){padding:5px 20px}.ibo-alert:not(.ibo-is-opened) .ibo-alert--title{padding-bottom:0}.ibo-alert:not(.ibo-is-opened) .ibo-alert--minimize-button{display:none}.ibo-alert:not(.ibo-is-opened) .ibo-alert--maximize-button{display:block}.ibo-alert:not(.ibo-is-opened) .ibo-alert--body{display:none}.ibo-alert--title+.ibo-alert--body{margin-top:4px}.ibo-alert--action-button{position:absolute;cursor:pointer;top:5px}.ibo-alert--action-button:hover i{opacity:0.8}.ibo-alert--action-button.ibo-alert--maximize-button,.ibo-alert--action-button.ibo-alert--minimize-button{right:30px}.ibo-alert--action-button.ibo-alert--close-button{right:10px}.ibo-button.ibo-is-regular.ibo-is-neutral,.ui-dialog .ibo-is-regular.ibo-is-neutral.ui-button,.ui-dialog .ibo-is-neutral.ui-button,.ui-dialog .ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-is-neutral.ui-button.ui-datepicker-current,.ui-dialog .ui-button.ui-datepicker-current.ui-dialog-titlebar-close,.ui-dialog .ibo-is-neutral.ui-button.ui-datepicker-close,.ui-dialog .ui-button.ui-datepicker-close.ui-dialog-titlebar-close,.ui-dialog .ibo-is-regular.ui-button.ui-dialog-titlebar-close,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close,.ibo-is-regular.ibo-is-neutral.ui-datepicker-current,.ui-dialog .ibo-is-neutral.ui-datepicker-current.ui-button,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close,.ibo-is-neutral.ui-datepicker-current,.ibo-is-neutral.ui-datepicker-current.ui-datepicker-close,.ui-dialog .ui-datepicker-current.ui-datepicker-close.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-is-regular.ui-datepicker-current.ui-button.ui-dialog-titlebar-close,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close.ui-datepicker-close,.ibo-is-regular.ibo-is-neutral.ui-datepicker-close,.ui-dialog .ibo-is-neutral.ui-datepicker-close.ui-button,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close,.ibo-is-neutral.ui-datepicker-close.ui-datepicker-current,.ui-dialog .ui-datepicker-close.ui-datepicker-current.ui-button.ui-dialog-titlebar-close,.ibo-is-neutral.ui-datepicker-close,.ui-dialog .ibo-is-regular.ui-datepicker-close.ui-button.ui-dialog-titlebar-close,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close.ui-datepicker-current,.ui-dialog .ibo-button.ibo-is-neutral.ui-button,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close,.ibo-button.ibo-is-neutral.ui-datepicker-current,.ui-dialog .ibo-button.ui-datepicker-current.ui-button.ui-dialog-titlebar-close,.ibo-button.ibo-is-neutral.ui-datepicker-close,.ui-dialog .ibo-button.ui-datepicker-close.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-button.ibo-is-regular.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-is-regular.ui-button.ui-dialog-titlebar-close.ui-datepicker-current,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current.ui-datepicker-close,.ui-dialog .ibo-is-regular.ui-button.ui-dialog-titlebar-close.ui-datepicker-close,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close.ui-datepicker-current,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close.ui-datepicker-current,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close.ui-datepicker-close{background-color:#f8f9fa;color:#212934;box-shadow:0px 2px 0px #d5dde5}.ibo-button.ibo-is-regular.ibo-is-neutral:hover,.ui-dialog .ibo-is-regular.ibo-is-neutral.ui-button:hover,.ui-dialog .ibo-is-neutral.ui-button:hover,.ui-dialog .ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-is-neutral.ui-button.ui-datepicker-current:hover,.ui-dialog .ui-button.ui-datepicker-current.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-is-neutral.ui-button.ui-datepicker-close:hover,.ui-dialog .ui-button.ui-datepicker-close.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-is-regular.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current:hover,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close:hover,.ibo-is-regular.ibo-is-neutral.ui-datepicker-current:hover,.ui-dialog .ibo-is-neutral.ui-datepicker-current.ui-button:hover,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close:hover,.ibo-is-neutral.ui-datepicker-current:hover,.ibo-is-neutral.ui-datepicker-current.ui-datepicker-close:hover,.ui-dialog .ui-datepicker-current.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-is-regular.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:hover,.ibo-is-regular.ibo-is-neutral.ui-datepicker-close:hover,.ui-dialog .ibo-is-neutral.ui-datepicker-close.ui-button:hover,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close:hover,.ibo-is-neutral.ui-datepicker-close.ui-datepicker-current:hover,.ui-dialog .ui-datepicker-close.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:hover,.ibo-is-neutral.ui-datepicker-close:hover,.ui-dialog .ibo-is-regular.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:hover,.ui-dialog .ibo-button.ibo-is-neutral.ui-button:hover,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close:hover,.ibo-button.ibo-is-neutral.ui-datepicker-current:hover,.ui-dialog .ibo-button.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:hover,.ibo-button.ibo-is-neutral.ui-datepicker-close:hover,.ui-dialog .ibo-button.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-button.ibo-is-regular.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-is-regular.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:hover,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current.ui-datepicker-close:hover,.ui-dialog .ibo-is-regular.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:hover,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close.ui-datepicker-current:hover,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:hover,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:hover{background-color:#e1e7ec;color:#212934;box-shadow:0px 2px 0px #d5dde5}.ibo-button.ibo-is-regular.ibo-is-neutral:active,.ui-dialog .ibo-is-regular.ibo-is-neutral.ui-button:active,.ui-dialog .ibo-is-neutral.ui-button:active,.ui-dialog .ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-is-neutral.ui-button.ui-datepicker-current:active,.ui-dialog .ui-button.ui-datepicker-current.ui-dialog-titlebar-close:active,.ui-dialog .ibo-is-neutral.ui-button.ui-datepicker-close:active,.ui-dialog .ui-button.ui-datepicker-close.ui-dialog-titlebar-close:active,.ui-dialog .ibo-is-regular.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current:active,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close:active,.ibo-is-regular.ibo-is-neutral.ui-datepicker-current:active,.ui-dialog .ibo-is-neutral.ui-datepicker-current.ui-button:active,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close:active,.ibo-is-neutral.ui-datepicker-current:active,.ibo-is-neutral.ui-datepicker-current.ui-datepicker-close:active,.ui-dialog .ui-datepicker-current.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-is-regular.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:active,.ibo-is-regular.ibo-is-neutral.ui-datepicker-close:active,.ui-dialog .ibo-is-neutral.ui-datepicker-close.ui-button:active,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close:active,.ibo-is-neutral.ui-datepicker-close.ui-datepicker-current:active,.ui-dialog .ui-datepicker-close.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:active,.ibo-is-neutral.ui-datepicker-close:active,.ui-dialog .ibo-is-regular.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:active,.ui-dialog .ibo-button.ibo-is-neutral.ui-button:active,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close:active,.ibo-button.ibo-is-neutral.ui-datepicker-current:active,.ui-dialog .ibo-button.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:active,.ibo-button.ibo-is-neutral.ui-datepicker-close:active,.ui-dialog .ibo-button.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-button.ibo-is-regular.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-is-regular.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:active,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current.ui-datepicker-close:active,.ui-dialog .ibo-is-regular.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:active,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close.ui-datepicker-current:active,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:active,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:active{background-color:#e1e7ec;color:#212934;box-shadow:inset 0px 2px 0px #d5dde5 , 0px 2px 0px #e1e7ec}.ibo-button.ibo-is-regular.ibo-is-neutral:disabled,.ui-dialog .ibo-is-regular.ibo-is-neutral.ui-button:disabled,.ui-dialog .ibo-is-neutral.ui-button:disabled,.ui-dialog .ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-is-neutral.ui-button.ui-datepicker-current:disabled,.ui-dialog .ui-button.ui-datepicker-current.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-is-neutral.ui-button.ui-datepicker-close:disabled,.ui-dialog .ui-button.ui-datepicker-close.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-is-regular.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current:disabled,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close:disabled,.ibo-is-regular.ibo-is-neutral.ui-datepicker-current:disabled,.ui-dialog .ibo-is-neutral.ui-datepicker-current.ui-button:disabled,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close:disabled,.ibo-is-neutral.ui-datepicker-current:disabled,.ibo-is-neutral.ui-datepicker-current.ui-datepicker-close:disabled,.ui-dialog .ui-datepicker-current.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-is-regular.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:disabled,.ibo-is-regular.ibo-is-neutral.ui-datepicker-close:disabled,.ui-dialog .ibo-is-neutral.ui-datepicker-close.ui-button:disabled,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close:disabled,.ibo-is-neutral.ui-datepicker-close.ui-datepicker-current:disabled,.ui-dialog .ui-datepicker-close.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:disabled,.ibo-is-neutral.ui-datepicker-close:disabled,.ui-dialog .ibo-is-regular.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:disabled,.ui-dialog .ibo-button.ibo-is-neutral.ui-button:disabled,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close:disabled,.ibo-button.ibo-is-neutral.ui-datepicker-current:disabled,.ui-dialog .ibo-button.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:disabled,.ibo-button.ibo-is-neutral.ui-datepicker-close:disabled,.ui-dialog .ibo-button.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-button.ibo-is-regular.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-is-regular.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:disabled,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current.ui-datepicker-close:disabled,.ui-dialog .ibo-is-regular.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:disabled,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close.ui-datepicker-current:disabled,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:disabled,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:disabled{background-color:#d5dde5;color:#6e7a8a;box-shadow:inset 0px 2px 0px #d5dde5}.ibo-button.ibo-is-regular.ibo-is-primary,.ui-dialog .ibo-is-regular.ibo-is-primary.ui-button,.ui-dialog .ibo-is-primary.ui-button,.ui-dialog .ibo-is-primary.ui-button.ui-datepicker-current,.ui-dialog .ibo-is-primary.ui-button.ui-datepicker-close,.ibo-is-regular.ibo-is-primary.ui-datepicker-current,.ui-dialog .ibo-is-primary.ui-datepicker-current.ui-button,.ibo-is-primary.ui-datepicker-current,.ibo-is-primary.ui-datepicker-current.ui-datepicker-close,.ibo-is-regular.ibo-is-primary.ui-datepicker-close,.ui-dialog .ibo-is-primary.ui-datepicker-close.ui-button,.ibo-is-primary.ui-datepicker-close.ui-datepicker-current,.ibo-is-primary.ui-datepicker-close,.ui-dialog .ibo-button.ibo-is-primary.ui-button,.ibo-button.ibo-is-primary.ui-datepicker-current,.ibo-button.ibo-is-primary.ui-datepicker-close{background-color:#00838f;color:white;box-shadow:0px 2px 0px #003636}.ibo-button.ibo-is-regular.ibo-is-primary:hover,.ui-dialog .ibo-is-regular.ibo-is-primary.ui-button:hover,.ui-dialog .ibo-is-primary.ui-button:hover,.ui-dialog .ibo-is-primary.ui-button.ui-datepicker-current:hover,.ui-dialog .ibo-is-primary.ui-button.ui-datepicker-close:hover,.ibo-is-regular.ibo-is-primary.ui-datepicker-current:hover,.ui-dialog .ibo-is-primary.ui-datepicker-current.ui-button:hover,.ibo-is-primary.ui-datepicker-current:hover,.ibo-is-primary.ui-datepicker-current.ui-datepicker-close:hover,.ibo-is-regular.ibo-is-primary.ui-datepicker-close:hover,.ui-dialog .ibo-is-primary.ui-datepicker-close.ui-button:hover,.ibo-is-primary.ui-datepicker-close.ui-datepicker-current:hover,.ibo-is-primary.ui-datepicker-close:hover,.ui-dialog .ibo-button.ibo-is-primary.ui-button:hover,.ibo-button.ibo-is-primary.ui-datepicker-current:hover,.ibo-button.ibo-is-primary.ui-datepicker-close:hover{background-color:#006164;color:white;box-shadow:0px 2px 0px #003636}.ibo-button.ibo-is-regular.ibo-is-primary:active,.ui-dialog .ibo-is-regular.ibo-is-primary.ui-button:active,.ui-dialog .ibo-is-primary.ui-button:active,.ui-dialog .ibo-is-primary.ui-button.ui-datepicker-current:active,.ui-dialog .ibo-is-primary.ui-button.ui-datepicker-close:active,.ibo-is-regular.ibo-is-primary.ui-datepicker-current:active,.ui-dialog .ibo-is-primary.ui-datepicker-current.ui-button:active,.ibo-is-primary.ui-datepicker-current:active,.ibo-is-primary.ui-datepicker-current.ui-datepicker-close:active,.ibo-is-regular.ibo-is-primary.ui-datepicker-close:active,.ui-dialog .ibo-is-primary.ui-datepicker-close.ui-button:active,.ibo-is-primary.ui-datepicker-close.ui-datepicker-current:active,.ibo-is-primary.ui-datepicker-close:active,.ui-dialog .ibo-button.ibo-is-primary.ui-button:active,.ibo-button.ibo-is-primary.ui-datepicker-current:active,.ibo-button.ibo-is-primary.ui-datepicker-close:active{background-color:#006164;color:white;box-shadow:inset 0px 2px 0px #003636 , 0px 2px 0px #006164}.ibo-button.ibo-is-regular.ibo-is-primary:disabled,.ui-dialog .ibo-is-regular.ibo-is-primary.ui-button:disabled,.ui-dialog .ibo-is-primary.ui-button:disabled,.ui-dialog .ibo-is-primary.ui-button.ui-datepicker-current:disabled,.ui-dialog .ibo-is-primary.ui-button.ui-datepicker-close:disabled,.ibo-is-regular.ibo-is-primary.ui-datepicker-current:disabled,.ui-dialog .ibo-is-primary.ui-datepicker-current.ui-button:disabled,.ibo-is-primary.ui-datepicker-current:disabled,.ibo-is-primary.ui-datepicker-current.ui-datepicker-close:disabled,.ibo-is-regular.ibo-is-primary.ui-datepicker-close:disabled,.ui-dialog .ibo-is-primary.ui-datepicker-close.ui-button:disabled,.ibo-is-primary.ui-datepicker-close.ui-datepicker-current:disabled,.ibo-is-primary.ui-datepicker-close:disabled,.ui-dialog .ibo-button.ibo-is-primary.ui-button:disabled,.ibo-button.ibo-is-primary.ui-datepicker-current:disabled,.ibo-button.ibo-is-primary.ui-datepicker-close:disabled{background-color:#d5dde5;color:#6e7a8a;box-shadow:inset 0px 2px 0px #d5dde5}.ibo-button.ibo-is-regular.ibo-is-secondary,.ui-dialog .ibo-is-regular.ibo-is-secondary.ui-button,.ui-dialog .ibo-is-secondary.ui-button,.ui-dialog .ui-button,.ui-dialog .ui-button.ui-datepicker-current,.ui-dialog .ui-button.ui-datepicker-close,.ui-dialog .ibo-is-secondary.ui-button.ui-datepicker-current,.ui-dialog .ui-button.ui-datepicker-current.ui-datepicker-close,.ui-dialog .ibo-is-secondary.ui-button.ui-datepicker-close,.ui-dialog .ui-button.ui-datepicker-close.ui-datepicker-current,.ui-dialog .ibo-is-regular.ui-button,.ui-dialog .ibo-is-regular.ui-button.ui-datepicker-current,.ui-dialog .ibo-is-regular.ui-button.ui-datepicker-close,.ibo-is-regular.ibo-is-secondary.ui-datepicker-current,.ui-dialog .ibo-is-secondary.ui-datepicker-current.ui-button,.ui-dialog .ui-datepicker-current.ui-button,.ui-dialog .ui-datepicker-current.ui-button.ui-datepicker-close,.ibo-is-secondary.ui-datepicker-current,.ui-datepicker-current,.ui-datepicker-current.ui-datepicker-close,.ibo-is-secondary.ui-datepicker-current.ui-datepicker-close,.ui-dialog .ui-datepicker-current.ui-datepicker-close.ui-button,.ui-dialog .ibo-is-regular.ui-datepicker-current.ui-button,.ibo-is-regular.ui-datepicker-current,.ibo-is-regular.ui-datepicker-current.ui-datepicker-close,.ibo-is-regular.ibo-is-secondary.ui-datepicker-close,.ui-dialog .ibo-is-secondary.ui-datepicker-close.ui-button,.ui-dialog .ui-datepicker-close.ui-button,.ui-dialog .ui-datepicker-close.ui-button.ui-datepicker-current,.ibo-is-secondary.ui-datepicker-close.ui-datepicker-current,.ui-dialog .ui-datepicker-close.ui-datepicker-current.ui-button,.ui-datepicker-close.ui-datepicker-current,.ibo-is-secondary.ui-datepicker-close,.ui-datepicker-close,.ui-dialog .ibo-is-regular.ui-datepicker-close.ui-button,.ibo-is-regular.ui-datepicker-close.ui-datepicker-current,.ibo-is-regular.ui-datepicker-close,.ui-dialog .ibo-button.ibo-is-secondary.ui-button,.ui-dialog .ibo-button.ui-button,.ui-dialog .ibo-button.ui-button.ui-datepicker-current,.ui-dialog .ibo-button.ui-button.ui-datepicker-close,.ibo-button.ibo-is-secondary.ui-datepicker-current,.ui-dialog .ibo-button.ui-datepicker-current.ui-button,.ibo-button.ui-datepicker-current,.ibo-button.ui-datepicker-current.ui-datepicker-close,.ibo-button.ibo-is-secondary.ui-datepicker-close,.ui-dialog .ibo-button.ui-datepicker-close.ui-button,.ibo-button.ui-datepicker-close.ui-datepicker-current,.ibo-button.ui-datepicker-close,.ui-dialog .ibo-button.ibo-is-regular.ui-button,.ibo-button.ibo-is-regular.ui-datepicker-current,.ibo-button.ibo-is-regular.ui-datepicker-close{background-color:#f8f9fa;color:#212934;box-shadow:0px 2px 0px #d5dde5}.ibo-button.ibo-is-regular.ibo-is-secondary:hover,.ui-dialog .ibo-is-regular.ibo-is-secondary.ui-button:hover,.ui-dialog .ibo-is-secondary.ui-button:hover,.ui-dialog .ui-button:hover,.ui-dialog .ui-button.ui-datepicker-current:hover,.ui-dialog .ui-button.ui-datepicker-close:hover,.ui-dialog .ibo-is-secondary.ui-button.ui-datepicker-current:hover,.ui-dialog .ui-button.ui-datepicker-current.ui-datepicker-close:hover,.ui-dialog .ibo-is-secondary.ui-button.ui-datepicker-close:hover,.ui-dialog .ui-button.ui-datepicker-close.ui-datepicker-current:hover,.ui-dialog .ibo-is-regular.ui-button:hover,.ui-dialog .ibo-is-regular.ui-button.ui-datepicker-current:hover,.ui-dialog .ibo-is-regular.ui-button.ui-datepicker-close:hover,.ibo-is-regular.ibo-is-secondary.ui-datepicker-current:hover,.ui-dialog .ibo-is-secondary.ui-datepicker-current.ui-button:hover,.ui-dialog .ui-datepicker-current.ui-button:hover,.ui-dialog .ui-datepicker-current.ui-button.ui-datepicker-close:hover,.ibo-is-secondary.ui-datepicker-current:hover,.ui-datepicker-current:hover,.ui-datepicker-current.ui-datepicker-close:hover,.ibo-is-secondary.ui-datepicker-current.ui-datepicker-close:hover,.ui-dialog .ui-datepicker-current.ui-datepicker-close.ui-button:hover,.ui-dialog .ibo-is-regular.ui-datepicker-current.ui-button:hover,.ibo-is-regular.ui-datepicker-current:hover,.ibo-is-regular.ui-datepicker-current.ui-datepicker-close:hover,.ibo-is-regular.ibo-is-secondary.ui-datepicker-close:hover,.ui-dialog .ibo-is-secondary.ui-datepicker-close.ui-button:hover,.ui-dialog .ui-datepicker-close.ui-button:hover,.ui-dialog .ui-datepicker-close.ui-button.ui-datepicker-current:hover,.ibo-is-secondary.ui-datepicker-close.ui-datepicker-current:hover,.ui-dialog .ui-datepicker-close.ui-datepicker-current.ui-button:hover,.ui-datepicker-close.ui-datepicker-current:hover,.ibo-is-secondary.ui-datepicker-close:hover,.ui-datepicker-close:hover,.ui-dialog .ibo-is-regular.ui-datepicker-close.ui-button:hover,.ibo-is-regular.ui-datepicker-close.ui-datepicker-current:hover,.ibo-is-regular.ui-datepicker-close:hover,.ui-dialog .ibo-button.ibo-is-secondary.ui-button:hover,.ui-dialog .ibo-button.ui-button:hover,.ui-dialog .ibo-button.ui-button.ui-datepicker-current:hover,.ui-dialog .ibo-button.ui-button.ui-datepicker-close:hover,.ibo-button.ibo-is-secondary.ui-datepicker-current:hover,.ui-dialog .ibo-button.ui-datepicker-current.ui-button:hover,.ibo-button.ui-datepicker-current:hover,.ibo-button.ui-datepicker-current.ui-datepicker-close:hover,.ibo-button.ibo-is-secondary.ui-datepicker-close:hover,.ui-dialog .ibo-button.ui-datepicker-close.ui-button:hover,.ibo-button.ui-datepicker-close.ui-datepicker-current:hover,.ibo-button.ui-datepicker-close:hover,.ui-dialog .ibo-button.ibo-is-regular.ui-button:hover,.ibo-button.ibo-is-regular.ui-datepicker-current:hover,.ibo-button.ibo-is-regular.ui-datepicker-close:hover{background-color:#e1e7ec;color:#212934;box-shadow:0px 2px 0px #d5dde5}.ibo-button.ibo-is-regular.ibo-is-secondary:active,.ui-dialog .ibo-is-regular.ibo-is-secondary.ui-button:active,.ui-dialog .ibo-is-secondary.ui-button:active,.ui-dialog .ui-button:active,.ui-dialog .ui-button.ui-datepicker-current:active,.ui-dialog .ui-button.ui-datepicker-close:active,.ui-dialog .ibo-is-secondary.ui-button.ui-datepicker-current:active,.ui-dialog .ui-button.ui-datepicker-current.ui-datepicker-close:active,.ui-dialog .ibo-is-secondary.ui-button.ui-datepicker-close:active,.ui-dialog .ui-button.ui-datepicker-close.ui-datepicker-current:active,.ui-dialog .ibo-is-regular.ui-button:active,.ui-dialog .ibo-is-regular.ui-button.ui-datepicker-current:active,.ui-dialog .ibo-is-regular.ui-button.ui-datepicker-close:active,.ibo-is-regular.ibo-is-secondary.ui-datepicker-current:active,.ui-dialog .ibo-is-secondary.ui-datepicker-current.ui-button:active,.ui-dialog .ui-datepicker-current.ui-button:active,.ui-dialog .ui-datepicker-current.ui-button.ui-datepicker-close:active,.ibo-is-secondary.ui-datepicker-current:active,.ui-datepicker-current:active,.ui-datepicker-current.ui-datepicker-close:active,.ibo-is-secondary.ui-datepicker-current.ui-datepicker-close:active,.ui-dialog .ui-datepicker-current.ui-datepicker-close.ui-button:active,.ui-dialog .ibo-is-regular.ui-datepicker-current.ui-button:active,.ibo-is-regular.ui-datepicker-current:active,.ibo-is-regular.ui-datepicker-current.ui-datepicker-close:active,.ibo-is-regular.ibo-is-secondary.ui-datepicker-close:active,.ui-dialog .ibo-is-secondary.ui-datepicker-close.ui-button:active,.ui-dialog .ui-datepicker-close.ui-button:active,.ui-dialog .ui-datepicker-close.ui-button.ui-datepicker-current:active,.ibo-is-secondary.ui-datepicker-close.ui-datepicker-current:active,.ui-dialog .ui-datepicker-close.ui-datepicker-current.ui-button:active,.ui-datepicker-close.ui-datepicker-current:active,.ibo-is-secondary.ui-datepicker-close:active,.ui-datepicker-close:active,.ui-dialog .ibo-is-regular.ui-datepicker-close.ui-button:active,.ibo-is-regular.ui-datepicker-close.ui-datepicker-current:active,.ibo-is-regular.ui-datepicker-close:active,.ui-dialog .ibo-button.ibo-is-secondary.ui-button:active,.ui-dialog .ibo-button.ui-button:active,.ui-dialog .ibo-button.ui-button.ui-datepicker-current:active,.ui-dialog .ibo-button.ui-button.ui-datepicker-close:active,.ibo-button.ibo-is-secondary.ui-datepicker-current:active,.ui-dialog .ibo-button.ui-datepicker-current.ui-button:active,.ibo-button.ui-datepicker-current:active,.ibo-button.ui-datepicker-current.ui-datepicker-close:active,.ibo-button.ibo-is-secondary.ui-datepicker-close:active,.ui-dialog .ibo-button.ui-datepicker-close.ui-button:active,.ibo-button.ui-datepicker-close.ui-datepicker-current:active,.ibo-button.ui-datepicker-close:active,.ui-dialog .ibo-button.ibo-is-regular.ui-button:active,.ibo-button.ibo-is-regular.ui-datepicker-current:active,.ibo-button.ibo-is-regular.ui-datepicker-close:active{background-color:#e1e7ec;color:#212934;box-shadow:inset 0px 2px 0px #d5dde5 , 0px 2px 0px #e1e7ec}.ibo-button.ibo-is-regular.ibo-is-secondary:disabled,.ui-dialog .ibo-is-regular.ibo-is-secondary.ui-button:disabled,.ui-dialog .ibo-is-secondary.ui-button:disabled,.ui-dialog .ui-button:disabled,.ui-dialog .ui-button.ui-datepicker-current:disabled,.ui-dialog .ui-button.ui-datepicker-close:disabled,.ui-dialog .ibo-is-secondary.ui-button.ui-datepicker-current:disabled,.ui-dialog .ui-button.ui-datepicker-current.ui-datepicker-close:disabled,.ui-dialog .ibo-is-secondary.ui-button.ui-datepicker-close:disabled,.ui-dialog .ui-button.ui-datepicker-close.ui-datepicker-current:disabled,.ui-dialog .ibo-is-regular.ui-button:disabled,.ui-dialog .ibo-is-regular.ui-button.ui-datepicker-current:disabled,.ui-dialog .ibo-is-regular.ui-button.ui-datepicker-close:disabled,.ibo-is-regular.ibo-is-secondary.ui-datepicker-current:disabled,.ui-dialog .ibo-is-secondary.ui-datepicker-current.ui-button:disabled,.ui-dialog .ui-datepicker-current.ui-button:disabled,.ui-dialog .ui-datepicker-current.ui-button.ui-datepicker-close:disabled,.ibo-is-secondary.ui-datepicker-current:disabled,.ui-datepicker-current:disabled,.ui-datepicker-current.ui-datepicker-close:disabled,.ibo-is-secondary.ui-datepicker-current.ui-datepicker-close:disabled,.ui-dialog .ui-datepicker-current.ui-datepicker-close.ui-button:disabled,.ui-dialog .ibo-is-regular.ui-datepicker-current.ui-button:disabled,.ibo-is-regular.ui-datepicker-current:disabled,.ibo-is-regular.ui-datepicker-current.ui-datepicker-close:disabled,.ibo-is-regular.ibo-is-secondary.ui-datepicker-close:disabled,.ui-dialog .ibo-is-secondary.ui-datepicker-close.ui-button:disabled,.ui-dialog .ui-datepicker-close.ui-button:disabled,.ui-dialog .ui-datepicker-close.ui-button.ui-datepicker-current:disabled,.ibo-is-secondary.ui-datepicker-close.ui-datepicker-current:disabled,.ui-dialog .ui-datepicker-close.ui-datepicker-current.ui-button:disabled,.ui-datepicker-close.ui-datepicker-current:disabled,.ibo-is-secondary.ui-datepicker-close:disabled,.ui-datepicker-close:disabled,.ui-dialog .ibo-is-regular.ui-datepicker-close.ui-button:disabled,.ibo-is-regular.ui-datepicker-close.ui-datepicker-current:disabled,.ibo-is-regular.ui-datepicker-close:disabled,.ui-dialog .ibo-button.ibo-is-secondary.ui-button:disabled,.ui-dialog .ibo-button.ui-button:disabled,.ui-dialog .ibo-button.ui-button.ui-datepicker-current:disabled,.ui-dialog .ibo-button.ui-button.ui-datepicker-close:disabled,.ibo-button.ibo-is-secondary.ui-datepicker-current:disabled,.ui-dialog .ibo-button.ui-datepicker-current.ui-button:disabled,.ibo-button.ui-datepicker-current:disabled,.ibo-button.ui-datepicker-current.ui-datepicker-close:disabled,.ibo-button.ibo-is-secondary.ui-datepicker-close:disabled,.ui-dialog .ibo-button.ui-datepicker-close.ui-button:disabled,.ibo-button.ui-datepicker-close.ui-datepicker-current:disabled,.ibo-button.ui-datepicker-close:disabled,.ui-dialog .ibo-button.ibo-is-regular.ui-button:disabled,.ibo-button.ibo-is-regular.ui-datepicker-current:disabled,.ibo-button.ibo-is-regular.ui-datepicker-close:disabled{background-color:#d5dde5;color:#6e7a8a;box-shadow:inset 0px 2px 0px #d5dde5}.ibo-button.ibo-is-regular.ibo-is-danger,.ui-dialog .ibo-is-regular.ibo-is-danger.ui-button,.ui-dialog .ibo-is-danger.ui-button,.ui-dialog .ibo-is-danger.ui-button.ui-datepicker-current,.ui-dialog .ibo-is-danger.ui-button.ui-datepicker-close,.ibo-is-regular.ibo-is-danger.ui-datepicker-current,.ui-dialog .ibo-is-danger.ui-datepicker-current.ui-button,.ibo-is-danger.ui-datepicker-current,.ibo-is-danger.ui-datepicker-current.ui-datepicker-close,.ibo-is-regular.ibo-is-danger.ui-datepicker-close,.ui-dialog .ibo-is-danger.ui-datepicker-close.ui-button,.ibo-is-danger.ui-datepicker-close.ui-datepicker-current,.ibo-is-danger.ui-datepicker-close,.ui-dialog .ibo-button.ibo-is-danger.ui-button,.ibo-button.ibo-is-danger.ui-datepicker-current,.ibo-button.ibo-is-danger.ui-datepicker-close{background-color:#c53030;color:white;box-shadow:0px 2px 0px #742a2a}.ibo-button.ibo-is-regular.ibo-is-danger:hover,.ui-dialog .ibo-is-regular.ibo-is-danger.ui-button:hover,.ui-dialog .ibo-is-danger.ui-button:hover,.ui-dialog .ibo-is-danger.ui-button.ui-datepicker-current:hover,.ui-dialog .ibo-is-danger.ui-button.ui-datepicker-close:hover,.ibo-is-regular.ibo-is-danger.ui-datepicker-current:hover,.ui-dialog .ibo-is-danger.ui-datepicker-current.ui-button:hover,.ibo-is-danger.ui-datepicker-current:hover,.ibo-is-danger.ui-datepicker-current.ui-datepicker-close:hover,.ibo-is-regular.ibo-is-danger.ui-datepicker-close:hover,.ui-dialog .ibo-is-danger.ui-datepicker-close.ui-button:hover,.ibo-is-danger.ui-datepicker-close.ui-datepicker-current:hover,.ibo-is-danger.ui-datepicker-close:hover,.ui-dialog .ibo-button.ibo-is-danger.ui-button:hover,.ibo-button.ibo-is-danger.ui-datepicker-current:hover,.ibo-button.ibo-is-danger.ui-datepicker-close:hover{background-color:#9b2c2c;color:white;box-shadow:0px 2px 0px #742a2a}.ibo-button.ibo-is-regular.ibo-is-danger:active,.ui-dialog .ibo-is-regular.ibo-is-danger.ui-button:active,.ui-dialog .ibo-is-danger.ui-button:active,.ui-dialog .ibo-is-danger.ui-button.ui-datepicker-current:active,.ui-dialog .ibo-is-danger.ui-button.ui-datepicker-close:active,.ibo-is-regular.ibo-is-danger.ui-datepicker-current:active,.ui-dialog .ibo-is-danger.ui-datepicker-current.ui-button:active,.ibo-is-danger.ui-datepicker-current:active,.ibo-is-danger.ui-datepicker-current.ui-datepicker-close:active,.ibo-is-regular.ibo-is-danger.ui-datepicker-close:active,.ui-dialog .ibo-is-danger.ui-datepicker-close.ui-button:active,.ibo-is-danger.ui-datepicker-close.ui-datepicker-current:active,.ibo-is-danger.ui-datepicker-close:active,.ui-dialog .ibo-button.ibo-is-danger.ui-button:active,.ibo-button.ibo-is-danger.ui-datepicker-current:active,.ibo-button.ibo-is-danger.ui-datepicker-close:active{background-color:#9b2c2c;color:white;box-shadow:inset 0px 2px 0px #742a2a , 0px 2px 0px #9b2c2c}.ibo-button.ibo-is-regular.ibo-is-danger:disabled,.ui-dialog .ibo-is-regular.ibo-is-danger.ui-button:disabled,.ui-dialog .ibo-is-danger.ui-button:disabled,.ui-dialog .ibo-is-danger.ui-button.ui-datepicker-current:disabled,.ui-dialog .ibo-is-danger.ui-button.ui-datepicker-close:disabled,.ibo-is-regular.ibo-is-danger.ui-datepicker-current:disabled,.ui-dialog .ibo-is-danger.ui-datepicker-current.ui-button:disabled,.ibo-is-danger.ui-datepicker-current:disabled,.ibo-is-danger.ui-datepicker-current.ui-datepicker-close:disabled,.ibo-is-regular.ibo-is-danger.ui-datepicker-close:disabled,.ui-dialog .ibo-is-danger.ui-datepicker-close.ui-button:disabled,.ibo-is-danger.ui-datepicker-close.ui-datepicker-current:disabled,.ibo-is-danger.ui-datepicker-close:disabled,.ui-dialog .ibo-button.ibo-is-danger.ui-button:disabled,.ibo-button.ibo-is-danger.ui-datepicker-current:disabled,.ibo-button.ibo-is-danger.ui-datepicker-close:disabled{background-color:#d5dde5;color:#6e7a8a;box-shadow:inset 0px 2px 0px #d5dde5}.ibo-button.ibo-is-regular.ibo-is-success,.ui-dialog .ibo-is-regular.ibo-is-success.ui-button,.ui-dialog .ibo-is-success.ui-button,.ui-dialog .ibo-is-success.ui-button.ui-datepicker-current,.ui-dialog .ibo-is-success.ui-button.ui-datepicker-close,.ibo-is-regular.ibo-is-success.ui-datepicker-current,.ui-dialog .ibo-is-success.ui-datepicker-current.ui-button,.ibo-is-success.ui-datepicker-current,.ibo-is-success.ui-datepicker-current.ui-datepicker-close,.ibo-is-regular.ibo-is-success.ui-datepicker-close,.ui-dialog .ibo-is-success.ui-datepicker-close.ui-button,.ibo-is-success.ui-datepicker-close.ui-datepicker-current,.ibo-is-success.ui-datepicker-close,.ui-dialog .ibo-button.ibo-is-success.ui-button,.ibo-button.ibo-is-success.ui-datepicker-current,.ibo-button.ibo-is-success.ui-datepicker-close{background-color:#558b2f;color:white;box-shadow:0px 2px 0px #235816}.ibo-button.ibo-is-regular.ibo-is-success:hover,.ui-dialog .ibo-is-regular.ibo-is-success.ui-button:hover,.ui-dialog .ibo-is-success.ui-button:hover,.ui-dialog .ibo-is-success.ui-button.ui-datepicker-current:hover,.ui-dialog .ibo-is-success.ui-button.ui-datepicker-close:hover,.ibo-is-regular.ibo-is-success.ui-datepicker-current:hover,.ui-dialog .ibo-is-success.ui-datepicker-current.ui-button:hover,.ibo-is-success.ui-datepicker-current:hover,.ibo-is-success.ui-datepicker-current.ui-datepicker-close:hover,.ibo-is-regular.ibo-is-success.ui-datepicker-close:hover,.ui-dialog .ibo-is-success.ui-datepicker-close.ui-button:hover,.ibo-is-success.ui-datepicker-close.ui-datepicker-current:hover,.ibo-is-success.ui-datepicker-close:hover,.ui-dialog .ibo-button.ibo-is-success.ui-button:hover,.ibo-button.ibo-is-success.ui-datepicker-current:hover,.ibo-button.ibo-is-success.ui-datepicker-close:hover{background-color:#33691e;color:white;box-shadow:0px 2px 0px #235816}.ibo-button.ibo-is-regular.ibo-is-success:active,.ui-dialog .ibo-is-regular.ibo-is-success.ui-button:active,.ui-dialog .ibo-is-success.ui-button:active,.ui-dialog .ibo-is-success.ui-button.ui-datepicker-current:active,.ui-dialog .ibo-is-success.ui-button.ui-datepicker-close:active,.ibo-is-regular.ibo-is-success.ui-datepicker-current:active,.ui-dialog .ibo-is-success.ui-datepicker-current.ui-button:active,.ibo-is-success.ui-datepicker-current:active,.ibo-is-success.ui-datepicker-current.ui-datepicker-close:active,.ibo-is-regular.ibo-is-success.ui-datepicker-close:active,.ui-dialog .ibo-is-success.ui-datepicker-close.ui-button:active,.ibo-is-success.ui-datepicker-close.ui-datepicker-current:active,.ibo-is-success.ui-datepicker-close:active,.ui-dialog .ibo-button.ibo-is-success.ui-button:active,.ibo-button.ibo-is-success.ui-datepicker-current:active,.ibo-button.ibo-is-success.ui-datepicker-close:active{background-color:#33691e;color:white;box-shadow:inset 0px 2px 0px #235816 , 0px 2px 0px #33691e}.ibo-button.ibo-is-regular.ibo-is-success:disabled,.ui-dialog .ibo-is-regular.ibo-is-success.ui-button:disabled,.ui-dialog .ibo-is-success.ui-button:disabled,.ui-dialog .ibo-is-success.ui-button.ui-datepicker-current:disabled,.ui-dialog .ibo-is-success.ui-button.ui-datepicker-close:disabled,.ibo-is-regular.ibo-is-success.ui-datepicker-current:disabled,.ui-dialog .ibo-is-success.ui-datepicker-current.ui-button:disabled,.ibo-is-success.ui-datepicker-current:disabled,.ibo-is-success.ui-datepicker-current.ui-datepicker-close:disabled,.ibo-is-regular.ibo-is-success.ui-datepicker-close:disabled,.ui-dialog .ibo-is-success.ui-datepicker-close.ui-button:disabled,.ibo-is-success.ui-datepicker-close.ui-datepicker-current:disabled,.ibo-is-success.ui-datepicker-close:disabled,.ui-dialog .ibo-button.ibo-is-success.ui-button:disabled,.ibo-button.ibo-is-success.ui-datepicker-current:disabled,.ibo-button.ibo-is-success.ui-datepicker-close:disabled{background-color:#d5dde5;color:#6e7a8a;box-shadow:inset 0px 2px 0px #d5dde5}.ibo-button.ibo-is-regular.ibo-is-red,.ui-dialog .ibo-is-regular.ibo-is-red.ui-button,.ui-dialog .ibo-is-red.ui-button,.ui-dialog .ibo-is-red.ui-button.ui-datepicker-current,.ui-dialog .ibo-is-red.ui-button.ui-datepicker-close,.ibo-is-regular.ibo-is-red.ui-datepicker-current,.ui-dialog .ibo-is-red.ui-datepicker-current.ui-button,.ibo-is-red.ui-datepicker-current,.ibo-is-red.ui-datepicker-current.ui-datepicker-close,.ibo-is-regular.ibo-is-red.ui-datepicker-close,.ui-dialog .ibo-is-red.ui-datepicker-close.ui-button,.ibo-is-red.ui-datepicker-close.ui-datepicker-current,.ibo-is-red.ui-datepicker-close,.ui-dialog .ibo-button.ibo-is-red.ui-button,.ibo-button.ibo-is-red.ui-datepicker-current,.ibo-button.ibo-is-red.ui-datepicker-close{background-color:#c53030;color:white;box-shadow:0px 2px 0px #742a2a}.ibo-button.ibo-is-regular.ibo-is-red:hover,.ui-dialog .ibo-is-regular.ibo-is-red.ui-button:hover,.ui-dialog .ibo-is-red.ui-button:hover,.ui-dialog .ibo-is-red.ui-button.ui-datepicker-current:hover,.ui-dialog .ibo-is-red.ui-button.ui-datepicker-close:hover,.ibo-is-regular.ibo-is-red.ui-datepicker-current:hover,.ui-dialog .ibo-is-red.ui-datepicker-current.ui-button:hover,.ibo-is-red.ui-datepicker-current:hover,.ibo-is-red.ui-datepicker-current.ui-datepicker-close:hover,.ibo-is-regular.ibo-is-red.ui-datepicker-close:hover,.ui-dialog .ibo-is-red.ui-datepicker-close.ui-button:hover,.ibo-is-red.ui-datepicker-close.ui-datepicker-current:hover,.ibo-is-red.ui-datepicker-close:hover,.ui-dialog .ibo-button.ibo-is-red.ui-button:hover,.ibo-button.ibo-is-red.ui-datepicker-current:hover,.ibo-button.ibo-is-red.ui-datepicker-close:hover{background-color:#9b2c2c;color:white;box-shadow:0px 2px 0px #742a2a}.ibo-button.ibo-is-regular.ibo-is-red:active,.ui-dialog .ibo-is-regular.ibo-is-red.ui-button:active,.ui-dialog .ibo-is-red.ui-button:active,.ui-dialog .ibo-is-red.ui-button.ui-datepicker-current:active,.ui-dialog .ibo-is-red.ui-button.ui-datepicker-close:active,.ibo-is-regular.ibo-is-red.ui-datepicker-current:active,.ui-dialog .ibo-is-red.ui-datepicker-current.ui-button:active,.ibo-is-red.ui-datepicker-current:active,.ibo-is-red.ui-datepicker-current.ui-datepicker-close:active,.ibo-is-regular.ibo-is-red.ui-datepicker-close:active,.ui-dialog .ibo-is-red.ui-datepicker-close.ui-button:active,.ibo-is-red.ui-datepicker-close.ui-datepicker-current:active,.ibo-is-red.ui-datepicker-close:active,.ui-dialog .ibo-button.ibo-is-red.ui-button:active,.ibo-button.ibo-is-red.ui-datepicker-current:active,.ibo-button.ibo-is-red.ui-datepicker-close:active{background-color:#9b2c2c;color:white;box-shadow:inset 0px 2px 0px #742a2a , 0px 2px 0px #9b2c2c}.ibo-button.ibo-is-regular.ibo-is-red:disabled,.ui-dialog .ibo-is-regular.ibo-is-red.ui-button:disabled,.ui-dialog .ibo-is-red.ui-button:disabled,.ui-dialog .ibo-is-red.ui-button.ui-datepicker-current:disabled,.ui-dialog .ibo-is-red.ui-button.ui-datepicker-close:disabled,.ibo-is-regular.ibo-is-red.ui-datepicker-current:disabled,.ui-dialog .ibo-is-red.ui-datepicker-current.ui-button:disabled,.ibo-is-red.ui-datepicker-current:disabled,.ibo-is-red.ui-datepicker-current.ui-datepicker-close:disabled,.ibo-is-regular.ibo-is-red.ui-datepicker-close:disabled,.ui-dialog .ibo-is-red.ui-datepicker-close.ui-button:disabled,.ibo-is-red.ui-datepicker-close.ui-datepicker-current:disabled,.ibo-is-red.ui-datepicker-close:disabled,.ui-dialog .ibo-button.ibo-is-red.ui-button:disabled,.ibo-button.ibo-is-red.ui-datepicker-current:disabled,.ibo-button.ibo-is-red.ui-datepicker-close:disabled{background-color:#d5dde5;color:#6e7a8a;box-shadow:inset 0px 2px 0px #d5dde5}.ibo-button.ibo-is-regular.ibo-is-green,.ui-dialog .ibo-is-regular.ibo-is-green.ui-button,.ui-dialog .ibo-is-green.ui-button,.ui-dialog .ibo-is-green.ui-button.ui-datepicker-current,.ui-dialog .ibo-is-green.ui-button.ui-datepicker-close,.ibo-is-regular.ibo-is-green.ui-datepicker-current,.ui-dialog .ibo-is-green.ui-datepicker-current.ui-button,.ibo-is-green.ui-datepicker-current,.ibo-is-green.ui-datepicker-current.ui-datepicker-close,.ibo-is-regular.ibo-is-green.ui-datepicker-close,.ui-dialog .ibo-is-green.ui-datepicker-close.ui-button,.ibo-is-green.ui-datepicker-close.ui-datepicker-current,.ibo-is-green.ui-datepicker-close,.ui-dialog .ibo-button.ibo-is-green.ui-button,.ibo-button.ibo-is-green.ui-datepicker-current,.ibo-button.ibo-is-green.ui-datepicker-close{background-color:#558b2f;color:white;box-shadow:0px 2px 0px #235816}.ibo-button.ibo-is-regular.ibo-is-green:hover,.ui-dialog .ibo-is-regular.ibo-is-green.ui-button:hover,.ui-dialog .ibo-is-green.ui-button:hover,.ui-dialog .ibo-is-green.ui-button.ui-datepicker-current:hover,.ui-dialog .ibo-is-green.ui-button.ui-datepicker-close:hover,.ibo-is-regular.ibo-is-green.ui-datepicker-current:hover,.ui-dialog .ibo-is-green.ui-datepicker-current.ui-button:hover,.ibo-is-green.ui-datepicker-current:hover,.ibo-is-green.ui-datepicker-current.ui-datepicker-close:hover,.ibo-is-regular.ibo-is-green.ui-datepicker-close:hover,.ui-dialog .ibo-is-green.ui-datepicker-close.ui-button:hover,.ibo-is-green.ui-datepicker-close.ui-datepicker-current:hover,.ibo-is-green.ui-datepicker-close:hover,.ui-dialog .ibo-button.ibo-is-green.ui-button:hover,.ibo-button.ibo-is-green.ui-datepicker-current:hover,.ibo-button.ibo-is-green.ui-datepicker-close:hover{background-color:#33691e;color:white;box-shadow:0px 2px 0px #235816}.ibo-button.ibo-is-regular.ibo-is-green:active,.ui-dialog .ibo-is-regular.ibo-is-green.ui-button:active,.ui-dialog .ibo-is-green.ui-button:active,.ui-dialog .ibo-is-green.ui-button.ui-datepicker-current:active,.ui-dialog .ibo-is-green.ui-button.ui-datepicker-close:active,.ibo-is-regular.ibo-is-green.ui-datepicker-current:active,.ui-dialog .ibo-is-green.ui-datepicker-current.ui-button:active,.ibo-is-green.ui-datepicker-current:active,.ibo-is-green.ui-datepicker-current.ui-datepicker-close:active,.ibo-is-regular.ibo-is-green.ui-datepicker-close:active,.ui-dialog .ibo-is-green.ui-datepicker-close.ui-button:active,.ibo-is-green.ui-datepicker-close.ui-datepicker-current:active,.ibo-is-green.ui-datepicker-close:active,.ui-dialog .ibo-button.ibo-is-green.ui-button:active,.ibo-button.ibo-is-green.ui-datepicker-current:active,.ibo-button.ibo-is-green.ui-datepicker-close:active{background-color:#33691e;color:white;box-shadow:inset 0px 2px 0px #235816 , 0px 2px 0px #33691e}.ibo-button.ibo-is-regular.ibo-is-green:disabled,.ui-dialog .ibo-is-regular.ibo-is-green.ui-button:disabled,.ui-dialog .ibo-is-green.ui-button:disabled,.ui-dialog .ibo-is-green.ui-button.ui-datepicker-current:disabled,.ui-dialog .ibo-is-green.ui-button.ui-datepicker-close:disabled,.ibo-is-regular.ibo-is-green.ui-datepicker-current:disabled,.ui-dialog .ibo-is-green.ui-datepicker-current.ui-button:disabled,.ibo-is-green.ui-datepicker-current:disabled,.ibo-is-green.ui-datepicker-current.ui-datepicker-close:disabled,.ibo-is-regular.ibo-is-green.ui-datepicker-close:disabled,.ui-dialog .ibo-is-green.ui-datepicker-close.ui-button:disabled,.ibo-is-green.ui-datepicker-close.ui-datepicker-current:disabled,.ibo-is-green.ui-datepicker-close:disabled,.ui-dialog .ibo-button.ibo-is-green.ui-button:disabled,.ibo-button.ibo-is-green.ui-datepicker-current:disabled,.ibo-button.ibo-is-green.ui-datepicker-close:disabled{background-color:#d5dde5;color:#6e7a8a;box-shadow:inset 0px 2px 0px #d5dde5}.ibo-button.ibo-is-regular.ibo-is-cyan,.ui-dialog .ibo-is-regular.ibo-is-cyan.ui-button,.ui-dialog .ibo-is-cyan.ui-button,.ui-dialog .ibo-is-cyan.ui-button.ui-datepicker-current,.ui-dialog .ibo-is-cyan.ui-button.ui-datepicker-close,.ibo-is-regular.ibo-is-cyan.ui-datepicker-current,.ui-dialog .ibo-is-cyan.ui-datepicker-current.ui-button,.ibo-is-cyan.ui-datepicker-current,.ibo-is-cyan.ui-datepicker-current.ui-datepicker-close,.ibo-is-regular.ibo-is-cyan.ui-datepicker-close,.ui-dialog .ibo-is-cyan.ui-datepicker-close.ui-button,.ibo-is-cyan.ui-datepicker-close.ui-datepicker-current,.ibo-is-cyan.ui-datepicker-close,.ui-dialog .ibo-button.ibo-is-cyan.ui-button,.ibo-button.ibo-is-cyan.ui-datepicker-current,.ibo-button.ibo-is-cyan.ui-datepicker-close{background-color:#00838f;color:white;box-shadow:0px 2px 0px #003636}.ibo-button.ibo-is-regular.ibo-is-cyan:hover,.ui-dialog .ibo-is-regular.ibo-is-cyan.ui-button:hover,.ui-dialog .ibo-is-cyan.ui-button:hover,.ui-dialog .ibo-is-cyan.ui-button.ui-datepicker-current:hover,.ui-dialog .ibo-is-cyan.ui-button.ui-datepicker-close:hover,.ibo-is-regular.ibo-is-cyan.ui-datepicker-current:hover,.ui-dialog .ibo-is-cyan.ui-datepicker-current.ui-button:hover,.ibo-is-cyan.ui-datepicker-current:hover,.ibo-is-cyan.ui-datepicker-current.ui-datepicker-close:hover,.ibo-is-regular.ibo-is-cyan.ui-datepicker-close:hover,.ui-dialog .ibo-is-cyan.ui-datepicker-close.ui-button:hover,.ibo-is-cyan.ui-datepicker-close.ui-datepicker-current:hover,.ibo-is-cyan.ui-datepicker-close:hover,.ui-dialog .ibo-button.ibo-is-cyan.ui-button:hover,.ibo-button.ibo-is-cyan.ui-datepicker-current:hover,.ibo-button.ibo-is-cyan.ui-datepicker-close:hover{background-color:#006164;color:white;box-shadow:0px 2px 0px #003636}.ibo-button.ibo-is-regular.ibo-is-cyan:active,.ui-dialog .ibo-is-regular.ibo-is-cyan.ui-button:active,.ui-dialog .ibo-is-cyan.ui-button:active,.ui-dialog .ibo-is-cyan.ui-button.ui-datepicker-current:active,.ui-dialog .ibo-is-cyan.ui-button.ui-datepicker-close:active,.ibo-is-regular.ibo-is-cyan.ui-datepicker-current:active,.ui-dialog .ibo-is-cyan.ui-datepicker-current.ui-button:active,.ibo-is-cyan.ui-datepicker-current:active,.ibo-is-cyan.ui-datepicker-current.ui-datepicker-close:active,.ibo-is-regular.ibo-is-cyan.ui-datepicker-close:active,.ui-dialog .ibo-is-cyan.ui-datepicker-close.ui-button:active,.ibo-is-cyan.ui-datepicker-close.ui-datepicker-current:active,.ibo-is-cyan.ui-datepicker-close:active,.ui-dialog .ibo-button.ibo-is-cyan.ui-button:active,.ibo-button.ibo-is-cyan.ui-datepicker-current:active,.ibo-button.ibo-is-cyan.ui-datepicker-close:active{background-color:#006164;color:white;box-shadow:inset 0px 2px 0px #003636 , 0px 2px 0px #006164}.ibo-button.ibo-is-regular.ibo-is-cyan:disabled,.ui-dialog .ibo-is-regular.ibo-is-cyan.ui-button:disabled,.ui-dialog .ibo-is-cyan.ui-button:disabled,.ui-dialog .ibo-is-cyan.ui-button.ui-datepicker-current:disabled,.ui-dialog .ibo-is-cyan.ui-button.ui-datepicker-close:disabled,.ibo-is-regular.ibo-is-cyan.ui-datepicker-current:disabled,.ui-dialog .ibo-is-cyan.ui-datepicker-current.ui-button:disabled,.ibo-is-cyan.ui-datepicker-current:disabled,.ibo-is-cyan.ui-datepicker-current.ui-datepicker-close:disabled,.ibo-is-regular.ibo-is-cyan.ui-datepicker-close:disabled,.ui-dialog .ibo-is-cyan.ui-datepicker-close.ui-button:disabled,.ibo-is-cyan.ui-datepicker-close.ui-datepicker-current:disabled,.ibo-is-cyan.ui-datepicker-close:disabled,.ui-dialog .ibo-button.ibo-is-cyan.ui-button:disabled,.ibo-button.ibo-is-cyan.ui-datepicker-current:disabled,.ibo-button.ibo-is-cyan.ui-datepicker-close:disabled{background-color:#d5dde5;color:#6e7a8a;box-shadow:inset 0px 2px 0px #d5dde5}.ibo-button.ibo-is-alternative.ibo-is-neutral,.ui-dialog .ibo-is-alternative.ibo-is-neutral.ui-button,.ui-dialog .ibo-is-neutral.ui-button.ui-dialog-titlebar-close,.ui-dialog .ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-is-alternative.ui-button.ui-dialog-titlebar-close,.ibo-is-alternative.ibo-is-neutral.ui-datepicker-current,.ui-dialog .ibo-is-neutral.ui-datepicker-current.ui-button.ui-dialog-titlebar-close,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-is-alternative.ui-datepicker-current.ui-button.ui-dialog-titlebar-close,.ibo-is-alternative.ibo-is-neutral.ui-datepicker-close,.ui-dialog .ibo-is-neutral.ui-datepicker-close.ui-button.ui-dialog-titlebar-close,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-is-alternative.ui-datepicker-close.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-button.ibo-is-neutral.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-is-neutral.ui-button.ui-dialog-titlebar-close.ui-datepicker-current,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current,.ui-dialog .ibo-is-neutral.ui-button.ui-dialog-titlebar-close.ui-datepicker-close,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-button.ibo-is-alternative.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-is-alternative.ui-button.ui-dialog-titlebar-close.ui-datepicker-current,.ui-dialog .ibo-is-alternative.ui-button.ui-dialog-titlebar-close.ui-datepicker-close{background-color:transparent;color:#212934;box-shadow:0px 2px 0px transparent}.ibo-button.ibo-is-alternative.ibo-is-neutral:hover,.ui-dialog .ibo-is-alternative.ibo-is-neutral.ui-button:hover,.ui-dialog .ibo-is-neutral.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-is-alternative.ui-button.ui-dialog-titlebar-close:hover,.ibo-is-alternative.ibo-is-neutral.ui-datepicker-current:hover,.ui-dialog .ibo-is-neutral.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-is-alternative.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:hover,.ibo-is-alternative.ibo-is-neutral.ui-datepicker-close:hover,.ui-dialog .ibo-is-neutral.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-is-alternative.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-button.ibo-is-neutral.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-is-neutral.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:hover,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current:hover,.ui-dialog .ibo-is-neutral.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:hover,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close:hover,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-button.ibo-is-alternative.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-is-alternative.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:hover,.ui-dialog .ibo-is-alternative.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:hover{background-color:#f8f9fa;color:#212934;box-shadow:0px 2px 0px #f8f9fa}.ibo-button.ibo-is-alternative.ibo-is-neutral:active,.ui-dialog .ibo-is-alternative.ibo-is-neutral.ui-button:active,.ui-dialog .ibo-is-neutral.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-is-alternative.ui-button.ui-dialog-titlebar-close:active,.ibo-is-alternative.ibo-is-neutral.ui-datepicker-current:active,.ui-dialog .ibo-is-neutral.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-is-alternative.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:active,.ibo-is-alternative.ibo-is-neutral.ui-datepicker-close:active,.ui-dialog .ibo-is-neutral.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-is-alternative.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-button.ibo-is-neutral.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-is-neutral.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:active,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current:active,.ui-dialog .ibo-is-neutral.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:active,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close:active,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-button.ibo-is-alternative.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-is-alternative.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:active,.ui-dialog .ibo-is-alternative.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:active{background-color:#f8f9fa;color:#212934;box-shadow:inset 0px 2px 0px #e1e7ec , 0px 2px 0px #f8f9fa}.ibo-button.ibo-is-alternative.ibo-is-neutral:disabled,.ui-dialog .ibo-is-alternative.ibo-is-neutral.ui-button:disabled,.ui-dialog .ibo-is-neutral.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-is-alternative.ui-button.ui-dialog-titlebar-close:disabled,.ibo-is-alternative.ibo-is-neutral.ui-datepicker-current:disabled,.ui-dialog .ibo-is-neutral.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-is-alternative.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:disabled,.ibo-is-alternative.ibo-is-neutral.ui-datepicker-close:disabled,.ui-dialog .ibo-is-neutral.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-is-alternative.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-button.ibo-is-neutral.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-is-neutral.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:disabled,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current:disabled,.ui-dialog .ibo-is-neutral.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:disabled,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close:disabled,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-button.ibo-is-alternative.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-is-alternative.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:disabled,.ui-dialog .ibo-is-alternative.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:disabled{background-color:transparent;color:#929fb1;box-shadow:inset 0px 2px 0px transparent}.ibo-button.ibo-is-alternative.ibo-is-primary,.ui-dialog .ibo-is-alternative.ibo-is-primary.ui-button,.ui-dialog .ibo-is-primary.ui-button.ui-dialog-titlebar-close,.ibo-is-alternative.ibo-is-primary.ui-datepicker-current,.ui-dialog .ibo-is-primary.ui-datepicker-current.ui-button.ui-dialog-titlebar-close,.ibo-is-alternative.ibo-is-primary.ui-datepicker-close,.ui-dialog .ibo-is-primary.ui-datepicker-close.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-button.ibo-is-primary.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-is-primary.ui-button.ui-dialog-titlebar-close.ui-datepicker-current,.ui-dialog .ibo-is-primary.ui-button.ui-dialog-titlebar-close.ui-datepicker-close{background-color:transparent;color:#006164;box-shadow:0px 2px 0px transparent}.ibo-button.ibo-is-alternative.ibo-is-primary:hover,.ui-dialog .ibo-is-alternative.ibo-is-primary.ui-button:hover,.ui-dialog .ibo-is-primary.ui-button.ui-dialog-titlebar-close:hover,.ibo-is-alternative.ibo-is-primary.ui-datepicker-current:hover,.ui-dialog .ibo-is-primary.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:hover,.ibo-is-alternative.ibo-is-primary.ui-datepicker-close:hover,.ui-dialog .ibo-is-primary.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-button.ibo-is-primary.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-is-primary.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:hover,.ui-dialog .ibo-is-primary.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:hover{background-color:white;color:#212934;box-shadow:0px 2px 0px white}.ibo-button.ibo-is-alternative.ibo-is-primary:active,.ui-dialog .ibo-is-alternative.ibo-is-primary.ui-button:active,.ui-dialog .ibo-is-primary.ui-button.ui-dialog-titlebar-close:active,.ibo-is-alternative.ibo-is-primary.ui-datepicker-current:active,.ui-dialog .ibo-is-primary.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:active,.ibo-is-alternative.ibo-is-primary.ui-datepicker-close:active,.ui-dialog .ibo-is-primary.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-button.ibo-is-primary.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-is-primary.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:active,.ui-dialog .ibo-is-primary.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:active{background-color:white;color:#212934;box-shadow:inset 0px 2px 0px white , 0px 2px 0px white}.ibo-button.ibo-is-alternative.ibo-is-primary:disabled,.ui-dialog .ibo-is-alternative.ibo-is-primary.ui-button:disabled,.ui-dialog .ibo-is-primary.ui-button.ui-dialog-titlebar-close:disabled,.ibo-is-alternative.ibo-is-primary.ui-datepicker-current:disabled,.ui-dialog .ibo-is-primary.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:disabled,.ibo-is-alternative.ibo-is-primary.ui-datepicker-close:disabled,.ui-dialog .ibo-is-primary.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-button.ibo-is-primary.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-is-primary.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:disabled,.ui-dialog .ibo-is-primary.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:disabled{background-color:transparent;color:#929fb1;box-shadow:inset 0px 2px 0px transparent}.ibo-button.ibo-is-alternative.ibo-is-secondary,.ui-dialog .ibo-is-alternative.ibo-is-secondary.ui-button,.ui-dialog .ibo-is-secondary.ui-button.ui-dialog-titlebar-close,.ui-dialog .ui-button.ui-dialog-titlebar-close,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close,.ui-dialog .ibo-is-alternative.ui-button,.ui-dialog .ibo-is-alternative.ui-button.ui-datepicker-current,.ui-dialog .ui-button.ui-datepicker-current.ui-dialog-titlebar-close,.ui-dialog .ibo-is-alternative.ui-button.ui-datepicker-close,.ui-dialog .ui-button.ui-datepicker-close.ui-dialog-titlebar-close,.ibo-is-alternative.ibo-is-secondary.ui-datepicker-current,.ui-dialog .ibo-is-secondary.ui-datepicker-current.ui-button.ui-dialog-titlebar-close,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close.ui-datepicker-close,.ui-dialog .ibo-is-alternative.ui-datepicker-current.ui-button,.ibo-is-alternative.ui-datepicker-current,.ibo-is-alternative.ui-datepicker-current.ui-datepicker-close,.ui-dialog .ui-datepicker-current.ui-datepicker-close.ui-button.ui-dialog-titlebar-close,.ibo-is-alternative.ibo-is-secondary.ui-datepicker-close,.ui-dialog .ibo-is-secondary.ui-datepicker-close.ui-button.ui-dialog-titlebar-close,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close.ui-datepicker-current,.ui-dialog .ibo-is-alternative.ui-datepicker-close.ui-button,.ibo-is-alternative.ui-datepicker-close.ui-datepicker-current,.ui-dialog .ui-datepicker-close.ui-datepicker-current.ui-button.ui-dialog-titlebar-close,.ibo-is-alternative.ui-datepicker-close,.ui-dialog .ibo-button.ibo-is-secondary.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-is-secondary.ui-button.ui-dialog-titlebar-close.ui-datepicker-current,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current.ui-datepicker-close,.ui-dialog .ibo-is-secondary.ui-button.ui-dialog-titlebar-close.ui-datepicker-close,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close.ui-datepicker-current,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close.ui-datepicker-current,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close.ui-datepicker-close,.ui-dialog .ibo-button.ibo-is-alternative.ui-button,.ibo-button.ibo-is-alternative.ui-datepicker-current,.ui-dialog .ibo-button.ui-datepicker-current.ui-button.ui-dialog-titlebar-close,.ibo-button.ibo-is-alternative.ui-datepicker-close,.ui-dialog .ibo-button.ui-datepicker-close.ui-button.ui-dialog-titlebar-close{background-color:transparent;color:#212934;box-shadow:0px 2px 0px transparent}.ibo-button.ibo-is-alternative.ibo-is-secondary:hover,.ui-dialog .ibo-is-alternative.ibo-is-secondary.ui-button:hover,.ui-dialog .ibo-is-secondary.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current:hover,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close:hover,.ui-dialog .ibo-is-alternative.ui-button:hover,.ui-dialog .ibo-is-alternative.ui-button.ui-datepicker-current:hover,.ui-dialog .ui-button.ui-datepicker-current.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-is-alternative.ui-button.ui-datepicker-close:hover,.ui-dialog .ui-button.ui-datepicker-close.ui-dialog-titlebar-close:hover,.ibo-is-alternative.ibo-is-secondary.ui-datepicker-current:hover,.ui-dialog .ibo-is-secondary.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:hover,.ui-dialog .ibo-is-alternative.ui-datepicker-current.ui-button:hover,.ibo-is-alternative.ui-datepicker-current:hover,.ibo-is-alternative.ui-datepicker-current.ui-datepicker-close:hover,.ui-dialog .ui-datepicker-current.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:hover,.ibo-is-alternative.ibo-is-secondary.ui-datepicker-close:hover,.ui-dialog .ibo-is-secondary.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:hover,.ui-dialog .ibo-is-alternative.ui-datepicker-close.ui-button:hover,.ibo-is-alternative.ui-datepicker-close.ui-datepicker-current:hover,.ui-dialog .ui-datepicker-close.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:hover,.ibo-is-alternative.ui-datepicker-close:hover,.ui-dialog .ibo-button.ibo-is-secondary.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-is-secondary.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:hover,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current.ui-datepicker-close:hover,.ui-dialog .ibo-is-secondary.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:hover,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close.ui-datepicker-current:hover,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:hover,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:hover,.ui-dialog .ibo-button.ibo-is-alternative.ui-button:hover,.ibo-button.ibo-is-alternative.ui-datepicker-current:hover,.ui-dialog .ibo-button.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:hover,.ibo-button.ibo-is-alternative.ui-datepicker-close:hover,.ui-dialog .ibo-button.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:hover{background-color:#f8f9fa;color:#212934;box-shadow:0px 2px 0px #f8f9fa}.ibo-button.ibo-is-alternative.ibo-is-secondary:active,.ui-dialog .ibo-is-alternative.ibo-is-secondary.ui-button:active,.ui-dialog .ibo-is-secondary.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current:active,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close:active,.ui-dialog .ibo-is-alternative.ui-button:active,.ui-dialog .ibo-is-alternative.ui-button.ui-datepicker-current:active,.ui-dialog .ui-button.ui-datepicker-current.ui-dialog-titlebar-close:active,.ui-dialog .ibo-is-alternative.ui-button.ui-datepicker-close:active,.ui-dialog .ui-button.ui-datepicker-close.ui-dialog-titlebar-close:active,.ibo-is-alternative.ibo-is-secondary.ui-datepicker-current:active,.ui-dialog .ibo-is-secondary.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:active,.ui-dialog .ibo-is-alternative.ui-datepicker-current.ui-button:active,.ibo-is-alternative.ui-datepicker-current:active,.ibo-is-alternative.ui-datepicker-current.ui-datepicker-close:active,.ui-dialog .ui-datepicker-current.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:active,.ibo-is-alternative.ibo-is-secondary.ui-datepicker-close:active,.ui-dialog .ibo-is-secondary.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:active,.ui-dialog .ibo-is-alternative.ui-datepicker-close.ui-button:active,.ibo-is-alternative.ui-datepicker-close.ui-datepicker-current:active,.ui-dialog .ui-datepicker-close.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:active,.ibo-is-alternative.ui-datepicker-close:active,.ui-dialog .ibo-button.ibo-is-secondary.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-is-secondary.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:active,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current.ui-datepicker-close:active,.ui-dialog .ibo-is-secondary.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:active,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close.ui-datepicker-current:active,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:active,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:active,.ui-dialog .ibo-button.ibo-is-alternative.ui-button:active,.ibo-button.ibo-is-alternative.ui-datepicker-current:active,.ui-dialog .ibo-button.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:active,.ibo-button.ibo-is-alternative.ui-datepicker-close:active,.ui-dialog .ibo-button.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:active{background-color:#f8f9fa;color:#212934;box-shadow:inset 0px 2px 0px #e1e7ec , 0px 2px 0px #f8f9fa}.ibo-button.ibo-is-alternative.ibo-is-secondary:disabled,.ui-dialog .ibo-is-alternative.ibo-is-secondary.ui-button:disabled,.ui-dialog .ibo-is-secondary.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current:disabled,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close:disabled,.ui-dialog .ibo-is-alternative.ui-button:disabled,.ui-dialog .ibo-is-alternative.ui-button.ui-datepicker-current:disabled,.ui-dialog .ui-button.ui-datepicker-current.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-is-alternative.ui-button.ui-datepicker-close:disabled,.ui-dialog .ui-button.ui-datepicker-close.ui-dialog-titlebar-close:disabled,.ibo-is-alternative.ibo-is-secondary.ui-datepicker-current:disabled,.ui-dialog .ibo-is-secondary.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ui-datepicker-current.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:disabled,.ui-dialog .ibo-is-alternative.ui-datepicker-current.ui-button:disabled,.ibo-is-alternative.ui-datepicker-current:disabled,.ibo-is-alternative.ui-datepicker-current.ui-datepicker-close:disabled,.ui-dialog .ui-datepicker-current.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:disabled,.ibo-is-alternative.ibo-is-secondary.ui-datepicker-close:disabled,.ui-dialog .ibo-is-secondary.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ui-datepicker-close.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:disabled,.ui-dialog .ibo-is-alternative.ui-datepicker-close.ui-button:disabled,.ibo-is-alternative.ui-datepicker-close.ui-datepicker-current:disabled,.ui-dialog .ui-datepicker-close.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:disabled,.ibo-is-alternative.ui-datepicker-close:disabled,.ui-dialog .ibo-button.ibo-is-secondary.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-is-secondary.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:disabled,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-current.ui-datepicker-close:disabled,.ui-dialog .ibo-is-secondary.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:disabled,.ui-dialog .ui-button.ui-dialog-titlebar-close.ui-datepicker-close.ui-datepicker-current:disabled,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:disabled,.ui-dialog .ibo-button.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:disabled,.ui-dialog .ibo-button.ibo-is-alternative.ui-button:disabled,.ibo-button.ibo-is-alternative.ui-datepicker-current:disabled,.ui-dialog .ibo-button.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:disabled,.ibo-button.ibo-is-alternative.ui-datepicker-close:disabled,.ui-dialog .ibo-button.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:disabled{background-color:transparent;color:#929fb1;box-shadow:inset 0px 2px 0px transparent}.ibo-button.ibo-is-alternative.ibo-is-danger,.ui-dialog .ibo-is-alternative.ibo-is-danger.ui-button,.ui-dialog .ibo-is-danger.ui-button.ui-dialog-titlebar-close,.ibo-is-alternative.ibo-is-danger.ui-datepicker-current,.ui-dialog .ibo-is-danger.ui-datepicker-current.ui-button.ui-dialog-titlebar-close,.ibo-is-alternative.ibo-is-danger.ui-datepicker-close,.ui-dialog .ibo-is-danger.ui-datepicker-close.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-button.ibo-is-danger.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-is-danger.ui-button.ui-dialog-titlebar-close.ui-datepicker-current,.ui-dialog .ibo-is-danger.ui-button.ui-dialog-titlebar-close.ui-datepicker-close{background-color:transparent;color:#c53030;box-shadow:0px 2px 0px transparent}.ibo-button.ibo-is-alternative.ibo-is-danger:hover,.ui-dialog .ibo-is-alternative.ibo-is-danger.ui-button:hover,.ui-dialog .ibo-is-danger.ui-button.ui-dialog-titlebar-close:hover,.ibo-is-alternative.ibo-is-danger.ui-datepicker-current:hover,.ui-dialog .ibo-is-danger.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:hover,.ibo-is-alternative.ibo-is-danger.ui-datepicker-close:hover,.ui-dialog .ibo-is-danger.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-button.ibo-is-danger.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-is-danger.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:hover,.ui-dialog .ibo-is-danger.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:hover{background-color:#fed7d7;color:#742a2a;box-shadow:0px 2px 0px #fed7d7}.ibo-button.ibo-is-alternative.ibo-is-danger:active,.ui-dialog .ibo-is-alternative.ibo-is-danger.ui-button:active,.ui-dialog .ibo-is-danger.ui-button.ui-dialog-titlebar-close:active,.ibo-is-alternative.ibo-is-danger.ui-datepicker-current:active,.ui-dialog .ibo-is-danger.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:active,.ibo-is-alternative.ibo-is-danger.ui-datepicker-close:active,.ui-dialog .ibo-is-danger.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-button.ibo-is-danger.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-is-danger.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:active,.ui-dialog .ibo-is-danger.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:active{background-color:#fed7d7;color:#742a2a;box-shadow:inset 0px 2px 0px #c53030 , 0px 2px 0px #fed7d7}.ibo-button.ibo-is-alternative.ibo-is-danger:disabled,.ui-dialog .ibo-is-alternative.ibo-is-danger.ui-button:disabled,.ui-dialog .ibo-is-danger.ui-button.ui-dialog-titlebar-close:disabled,.ibo-is-alternative.ibo-is-danger.ui-datepicker-current:disabled,.ui-dialog .ibo-is-danger.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:disabled,.ibo-is-alternative.ibo-is-danger.ui-datepicker-close:disabled,.ui-dialog .ibo-is-danger.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-button.ibo-is-danger.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-is-danger.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:disabled,.ui-dialog .ibo-is-danger.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:disabled{background-color:transparent;color:#929fb1;box-shadow:inset 0px 2px 0px transparent}.ibo-button.ibo-is-alternative.ibo-is-success,.ui-dialog .ibo-is-alternative.ibo-is-success.ui-button,.ui-dialog .ibo-is-success.ui-button.ui-dialog-titlebar-close,.ibo-is-alternative.ibo-is-success.ui-datepicker-current,.ui-dialog .ibo-is-success.ui-datepicker-current.ui-button.ui-dialog-titlebar-close,.ibo-is-alternative.ibo-is-success.ui-datepicker-close,.ui-dialog .ibo-is-success.ui-datepicker-close.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-button.ibo-is-success.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-is-success.ui-button.ui-dialog-titlebar-close.ui-datepicker-current,.ui-dialog .ibo-is-success.ui-button.ui-dialog-titlebar-close.ui-datepicker-close{background-color:transparent;color:#33691e;box-shadow:0px 2px 0px transparent}.ibo-button.ibo-is-alternative.ibo-is-success:hover,.ui-dialog .ibo-is-alternative.ibo-is-success.ui-button:hover,.ui-dialog .ibo-is-success.ui-button.ui-dialog-titlebar-close:hover,.ibo-is-alternative.ibo-is-success.ui-datepicker-current:hover,.ui-dialog .ibo-is-success.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:hover,.ibo-is-alternative.ibo-is-success.ui-datepicker-close:hover,.ui-dialog .ibo-is-success.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-button.ibo-is-success.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-is-success.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:hover,.ui-dialog .ibo-is-success.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:hover{background-color:#dcedc8;color:#33691e;box-shadow:0px 2px 0px #dcedc8}.ibo-button.ibo-is-alternative.ibo-is-success:active,.ui-dialog .ibo-is-alternative.ibo-is-success.ui-button:active,.ui-dialog .ibo-is-success.ui-button.ui-dialog-titlebar-close:active,.ibo-is-alternative.ibo-is-success.ui-datepicker-current:active,.ui-dialog .ibo-is-success.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:active,.ibo-is-alternative.ibo-is-success.ui-datepicker-close:active,.ui-dialog .ibo-is-success.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-button.ibo-is-success.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-is-success.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:active,.ui-dialog .ibo-is-success.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:active{background-color:#dcedc8;color:#33691e;box-shadow:inset 0px 2px 0px #689f38 , 0px 2px 0px #dcedc8}.ibo-button.ibo-is-alternative.ibo-is-success:disabled,.ui-dialog .ibo-is-alternative.ibo-is-success.ui-button:disabled,.ui-dialog .ibo-is-success.ui-button.ui-dialog-titlebar-close:disabled,.ibo-is-alternative.ibo-is-success.ui-datepicker-current:disabled,.ui-dialog .ibo-is-success.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:disabled,.ibo-is-alternative.ibo-is-success.ui-datepicker-close:disabled,.ui-dialog .ibo-is-success.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-button.ibo-is-success.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-is-success.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:disabled,.ui-dialog .ibo-is-success.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:disabled{background-color:transparent;color:#929fb1;box-shadow:inset 0px 2px 0px transparent}.ibo-button.ibo-is-alternative.ibo-is-red,.ui-dialog .ibo-is-alternative.ibo-is-red.ui-button,.ui-dialog .ibo-is-red.ui-button.ui-dialog-titlebar-close,.ibo-is-alternative.ibo-is-red.ui-datepicker-current,.ui-dialog .ibo-is-red.ui-datepicker-current.ui-button.ui-dialog-titlebar-close,.ibo-is-alternative.ibo-is-red.ui-datepicker-close,.ui-dialog .ibo-is-red.ui-datepicker-close.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-button.ibo-is-red.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-is-red.ui-button.ui-dialog-titlebar-close.ui-datepicker-current,.ui-dialog .ibo-is-red.ui-button.ui-dialog-titlebar-close.ui-datepicker-close{background-color:transparent;color:#c53030;box-shadow:0px 2px 0px transparent}.ibo-button.ibo-is-alternative.ibo-is-red:hover,.ui-dialog .ibo-is-alternative.ibo-is-red.ui-button:hover,.ui-dialog .ibo-is-red.ui-button.ui-dialog-titlebar-close:hover,.ibo-is-alternative.ibo-is-red.ui-datepicker-current:hover,.ui-dialog .ibo-is-red.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:hover,.ibo-is-alternative.ibo-is-red.ui-datepicker-close:hover,.ui-dialog .ibo-is-red.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-button.ibo-is-red.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-is-red.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:hover,.ui-dialog .ibo-is-red.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:hover{background-color:#fed7d7;color:#742a2a;box-shadow:0px 2px 0px #fed7d7}.ibo-button.ibo-is-alternative.ibo-is-red:active,.ui-dialog .ibo-is-alternative.ibo-is-red.ui-button:active,.ui-dialog .ibo-is-red.ui-button.ui-dialog-titlebar-close:active,.ibo-is-alternative.ibo-is-red.ui-datepicker-current:active,.ui-dialog .ibo-is-red.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:active,.ibo-is-alternative.ibo-is-red.ui-datepicker-close:active,.ui-dialog .ibo-is-red.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-button.ibo-is-red.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-is-red.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:active,.ui-dialog .ibo-is-red.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:active{background-color:#fed7d7;color:#742a2a;box-shadow:inset 0px 2px 0px #c53030 , 0px 2px 0px #fed7d7}.ibo-button.ibo-is-alternative.ibo-is-red:disabled,.ui-dialog .ibo-is-alternative.ibo-is-red.ui-button:disabled,.ui-dialog .ibo-is-red.ui-button.ui-dialog-titlebar-close:disabled,.ibo-is-alternative.ibo-is-red.ui-datepicker-current:disabled,.ui-dialog .ibo-is-red.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:disabled,.ibo-is-alternative.ibo-is-red.ui-datepicker-close:disabled,.ui-dialog .ibo-is-red.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-button.ibo-is-red.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-is-red.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:disabled,.ui-dialog .ibo-is-red.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:disabled{background-color:transparent;color:#929fb1;box-shadow:inset 0px 2px 0px transparent}.ibo-button.ibo-is-alternative.ibo-is-green,.ui-dialog .ibo-is-alternative.ibo-is-green.ui-button,.ui-dialog .ibo-is-green.ui-button.ui-dialog-titlebar-close,.ibo-is-alternative.ibo-is-green.ui-datepicker-current,.ui-dialog .ibo-is-green.ui-datepicker-current.ui-button.ui-dialog-titlebar-close,.ibo-is-alternative.ibo-is-green.ui-datepicker-close,.ui-dialog .ibo-is-green.ui-datepicker-close.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-button.ibo-is-green.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-is-green.ui-button.ui-dialog-titlebar-close.ui-datepicker-current,.ui-dialog .ibo-is-green.ui-button.ui-dialog-titlebar-close.ui-datepicker-close{background-color:transparent;color:#33691e;box-shadow:0px 2px 0px transparent}.ibo-button.ibo-is-alternative.ibo-is-green:hover,.ui-dialog .ibo-is-alternative.ibo-is-green.ui-button:hover,.ui-dialog .ibo-is-green.ui-button.ui-dialog-titlebar-close:hover,.ibo-is-alternative.ibo-is-green.ui-datepicker-current:hover,.ui-dialog .ibo-is-green.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:hover,.ibo-is-alternative.ibo-is-green.ui-datepicker-close:hover,.ui-dialog .ibo-is-green.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-button.ibo-is-green.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-is-green.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:hover,.ui-dialog .ibo-is-green.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:hover{background-color:#dcedc8;color:#33691e;box-shadow:0px 2px 0px #dcedc8}.ibo-button.ibo-is-alternative.ibo-is-green:active,.ui-dialog .ibo-is-alternative.ibo-is-green.ui-button:active,.ui-dialog .ibo-is-green.ui-button.ui-dialog-titlebar-close:active,.ibo-is-alternative.ibo-is-green.ui-datepicker-current:active,.ui-dialog .ibo-is-green.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:active,.ibo-is-alternative.ibo-is-green.ui-datepicker-close:active,.ui-dialog .ibo-is-green.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-button.ibo-is-green.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-is-green.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:active,.ui-dialog .ibo-is-green.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:active{background-color:#dcedc8;color:#33691e;box-shadow:inset 0px 2px 0px #689f38 , 0px 2px 0px #dcedc8}.ibo-button.ibo-is-alternative.ibo-is-green:disabled,.ui-dialog .ibo-is-alternative.ibo-is-green.ui-button:disabled,.ui-dialog .ibo-is-green.ui-button.ui-dialog-titlebar-close:disabled,.ibo-is-alternative.ibo-is-green.ui-datepicker-current:disabled,.ui-dialog .ibo-is-green.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:disabled,.ibo-is-alternative.ibo-is-green.ui-datepicker-close:disabled,.ui-dialog .ibo-is-green.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-button.ibo-is-green.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-is-green.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:disabled,.ui-dialog .ibo-is-green.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:disabled{background-color:transparent;color:#929fb1;box-shadow:inset 0px 2px 0px transparent}.ibo-button.ibo-is-alternative.ibo-is-cyan,.ui-dialog .ibo-is-alternative.ibo-is-cyan.ui-button,.ui-dialog .ibo-is-cyan.ui-button.ui-dialog-titlebar-close,.ibo-is-alternative.ibo-is-cyan.ui-datepicker-current,.ui-dialog .ibo-is-cyan.ui-datepicker-current.ui-button.ui-dialog-titlebar-close,.ibo-is-alternative.ibo-is-cyan.ui-datepicker-close,.ui-dialog .ibo-is-cyan.ui-datepicker-close.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-button.ibo-is-cyan.ui-button.ui-dialog-titlebar-close,.ui-dialog .ibo-is-cyan.ui-button.ui-dialog-titlebar-close.ui-datepicker-current,.ui-dialog .ibo-is-cyan.ui-button.ui-dialog-titlebar-close.ui-datepicker-close{background-color:transparent;color:#006164;box-shadow:0px 2px 0px transparent}.ibo-button.ibo-is-alternative.ibo-is-cyan:hover,.ui-dialog .ibo-is-alternative.ibo-is-cyan.ui-button:hover,.ui-dialog .ibo-is-cyan.ui-button.ui-dialog-titlebar-close:hover,.ibo-is-alternative.ibo-is-cyan.ui-datepicker-current:hover,.ui-dialog .ibo-is-cyan.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:hover,.ibo-is-alternative.ibo-is-cyan.ui-datepicker-close:hover,.ui-dialog .ibo-is-cyan.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-button.ibo-is-cyan.ui-button.ui-dialog-titlebar-close:hover,.ui-dialog .ibo-is-cyan.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:hover,.ui-dialog .ibo-is-cyan.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:hover{background-color:#c9eef2;color:#006164;box-shadow:0px 2px 0px #c9eef2}.ibo-button.ibo-is-alternative.ibo-is-cyan:active,.ui-dialog .ibo-is-alternative.ibo-is-cyan.ui-button:active,.ui-dialog .ibo-is-cyan.ui-button.ui-dialog-titlebar-close:active,.ibo-is-alternative.ibo-is-cyan.ui-datepicker-current:active,.ui-dialog .ibo-is-cyan.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:active,.ibo-is-alternative.ibo-is-cyan.ui-datepicker-close:active,.ui-dialog .ibo-is-cyan.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-button.ibo-is-cyan.ui-button.ui-dialog-titlebar-close:active,.ui-dialog .ibo-is-cyan.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:active,.ui-dialog .ibo-is-cyan.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:active{background-color:#c9eef2;color:#006164;box-shadow:inset 0px 2px 0px #00838f , 0px 2px 0px #c9eef2}.ibo-button.ibo-is-alternative.ibo-is-cyan:disabled,.ui-dialog .ibo-is-alternative.ibo-is-cyan.ui-button:disabled,.ui-dialog .ibo-is-cyan.ui-button.ui-dialog-titlebar-close:disabled,.ibo-is-alternative.ibo-is-cyan.ui-datepicker-current:disabled,.ui-dialog .ibo-is-cyan.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:disabled,.ibo-is-alternative.ibo-is-cyan.ui-datepicker-close:disabled,.ui-dialog .ibo-is-cyan.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-button.ibo-is-cyan.ui-button.ui-dialog-titlebar-close:disabled,.ui-dialog .ibo-is-cyan.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:disabled,.ui-dialog .ibo-is-cyan.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:disabled{background-color:transparent;color:#929fb1;box-shadow:inset 0px 2px 0px transparent}.ibo-button,.ui-dialog .ui-button,.ui-datepicker-current,.ui-datepicker-close{position:relative;display:inline-block;padding:6px 9px;border:0;border-radius:4px;cursor:pointer;text-transform:uppercase;white-space:nowrap}.ibo-button.ibo-action-button,.ui-dialog .ibo-action-button.ui-button,.ibo-action-button.ui-datepicker-current,.ibo-action-button.ui-datepicker-close{float:right}.ibo-button .ibo-button--loading-icon,.ui-dialog .ui-button .ibo-button--loading-icon,.ui-datepicker-current .ibo-button--loading-icon,.ui-datepicker-close .ibo-button--loading-icon{display:none}.ibo-button.ibo-is-loading .ibo-button--icon,.ui-dialog .ibo-is-loading.ui-button .ibo-button--icon,.ibo-is-loading.ui-datepicker-current .ibo-button--icon,.ibo-is-loading.ui-datepicker-close .ibo-button--icon{display:none}.ibo-button.ibo-is-loading .ibo-button--loading-icon,.ui-dialog .ibo-is-loading.ui-button .ibo-button--loading-icon,.ibo-is-loading.ui-datepicker-current .ibo-button--loading-icon,.ibo-is-loading.ui-datepicker-close .ibo-button--loading-icon{display:inline-block}.ibo-button.ibo-is-loading .ibo-button--loading-icon+.ibo-button--label,.ui-dialog .ibo-is-loading.ui-button .ibo-button--loading-icon+.ibo-button--label,.ibo-is-loading.ui-datepicker-current .ibo-button--loading-icon+.ibo-button--label,.ibo-is-loading.ui-datepicker-close .ibo-button--loading-icon+.ibo-button--label{margin-left:4px}.ibo-button--icon+.ibo-button--label{margin-left:4px}.ibo-button--vertical-align{margin-top:4px;margin-bottom:4px}.ibo-button-group{display:inline-flex;flex-wrap:nowrap}.ibo-button-group .ibo-button,.ibo-button-group .ui-dialog .ui-button,.ui-dialog .ibo-button-group .ui-button,.ibo-button-group .ui-datepicker-current,.ibo-button-group .ui-datepicker-close{position:relative}.ibo-button-group .ibo-button:first-child,.ibo-button-group .ui-dialog .ui-button:first-child,.ui-dialog .ibo-button-group .ui-button:first-child,.ibo-button-group .ui-datepicker-current:first-child,.ibo-button-group .ui-datepicker-close:first-child{border-radius:4px 0 0 4px}.ibo-button-group .ibo-button:last-child,.ibo-button-group .ui-dialog .ui-button:last-child,.ui-dialog .ibo-button-group .ui-button:last-child,.ibo-button-group .ui-datepicker-current:last-child,.ibo-button-group .ui-datepicker-close:last-child{border-radius:0 4px 4px 0}.ibo-button-group .ibo-button:not(:first-child):not(:last-child),.ibo-button-group .ui-dialog .ui-button:not(:first-child):not(:last-child),.ui-dialog .ibo-button-group .ui-button:not(:first-child):not(:last-child),.ibo-button-group .ui-datepicker-current:not(:first-child):not(:last-child),.ibo-button-group .ui-datepicker-close:not(:first-child):not(:last-child){border-radius:0}.ibo-button-group .ibo-button+.ibo-button,.ibo-button-group .ui-dialog .ui-button+.ibo-button,.ibo-button-group .ui-dialog .ui-dialog .ui-button+.ui-button,.ui-dialog .ibo-button-group .ui-dialog .ui-button+.ui-button,.ibo-button-group .ui-dialog .ui-button+.ui-datepicker-current,.ibo-button-group .ui-dialog .ui-button+.ui-datepicker-close,.ui-dialog .ibo-button-group .ui-button+.ibo-button,.ibo-button-group .ui-datepicker-current+.ibo-button,.ibo-button-group .ui-dialog .ui-datepicker-current+.ui-button,.ui-dialog .ibo-button-group .ui-datepicker-current+.ui-button,.ibo-button-group .ui-datepicker-current+.ui-datepicker-current,.ibo-button-group .ui-datepicker-current+.ui-datepicker-close,.ibo-button-group .ui-datepicker-close+.ibo-button,.ibo-button-group .ui-dialog .ui-datepicker-close+.ui-button,.ui-dialog .ibo-button-group .ui-datepicker-close+.ui-button,.ibo-button-group .ui-datepicker-close+.ui-datepicker-current,.ibo-button-group .ui-datepicker-close+.ui-datepicker-close,.ibo-button-group .ui-dialog .ibo-button+.ui-button,.ui-dialog .ibo-button-group .ibo-button+.ui-button,.ibo-button-group .ibo-button+.ui-datepicker-current,.ibo-button-group .ibo-button+.ui-datepicker-close{margin-left:0}.ibo-button-group .ibo-button+.ibo-button::before,.ibo-button-group .ui-dialog .ui-button+.ibo-button::before,.ui-dialog .ibo-button-group .ui-button+.ibo-button::before,.ibo-button-group .ui-datepicker-current+.ibo-button::before,.ibo-button-group .ui-datepicker-close+.ibo-button::before,.ibo-button-group .ui-dialog .ibo-button+.ui-button::before,.ui-dialog .ibo-button-group .ibo-button+.ui-button::before,.ibo-button-group .ibo-button+.ui-datepicker-current::before,.ibo-button-group .ibo-button+.ui-datepicker-close::before{content:"";position:absolute;top:6px;bottom:6px;left:0;width:1px;border-left:1px solid transparent}.ibo-button-group>*+*.ibo-is-regular.ibo-is-neutral::before,.ui-dialog .ibo-button-group>*+*.ibo-is-neutral.ui-button::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close::before,.ibo-button-group>*+*.ibo-is-neutral.ui-datepicker-current::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-current.ui-button.ui-dialog-titlebar-close::before,.ibo-button-group>*+*.ibo-is-neutral.ui-datepicker-close::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-close.ui-button.ui-dialog-titlebar-close::before,.ui-dialog .ibo-button-group>*+*.ibo-is-regular.ui-button.ui-dialog-titlebar-close::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close.ui-datepicker-current::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close.ui-datepicker-close::before{border-left-color:#d5dde5}.ibo-button-group>*+*.ibo-is-regular.ibo-is-neutral:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-neutral.ui-button:hover::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close:hover::before,.ibo-button-group>*+*.ibo-is-neutral.ui-datepicker-current:hover::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:hover::before,.ibo-button-group>*+*.ibo-is-neutral.ui-datepicker-close:hover::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-regular.ui-button.ui-dialog-titlebar-close:hover::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:hover::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:hover::before{border-left-color:#d5dde5}.ibo-button-group>*+*.ibo-is-regular.ibo-is-neutral:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-neutral.ui-button:active::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close:active::before,.ibo-button-group>*+*.ibo-is-neutral.ui-datepicker-current:active::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:active::before,.ibo-button-group>*+*.ibo-is-neutral.ui-datepicker-close:active::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-regular.ui-button.ui-dialog-titlebar-close:active::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:active::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:active::before{border-left-color:#e1e7ec}.ibo-button-group>*+*.ibo-is-regular.ibo-is-neutral:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-neutral.ui-button:disabled::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close:disabled::before,.ibo-button-group>*+*.ibo-is-neutral.ui-datepicker-current:disabled::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:disabled::before,.ibo-button-group>*+*.ibo-is-neutral.ui-datepicker-close:disabled::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-regular.ui-button.ui-dialog-titlebar-close:disabled::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:disabled::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:disabled::before{border-left-color:#aebecd}.ibo-button-group>*+*.ibo-is-regular.ibo-is-primary::before,.ui-dialog .ibo-button-group>*+*.ibo-is-primary.ui-button::before,.ibo-button-group>*+*.ibo-is-primary.ui-datepicker-current::before,.ibo-button-group>*+*.ibo-is-primary.ui-datepicker-close::before{border-left-color:#006164}.ibo-button-group>*+*.ibo-is-regular.ibo-is-primary:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-primary.ui-button:hover::before,.ibo-button-group>*+*.ibo-is-primary.ui-datepicker-current:hover::before,.ibo-button-group>*+*.ibo-is-primary.ui-datepicker-close:hover::before{border-left-color:#006164}.ibo-button-group>*+*.ibo-is-regular.ibo-is-primary:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-primary.ui-button:active::before,.ibo-button-group>*+*.ibo-is-primary.ui-datepicker-current:active::before,.ibo-button-group>*+*.ibo-is-primary.ui-datepicker-close:active::before{border-left-color:#006164}.ibo-button-group>*+*.ibo-is-regular.ibo-is-primary:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-primary.ui-button:disabled::before,.ibo-button-group>*+*.ibo-is-primary.ui-datepicker-current:disabled::before,.ibo-button-group>*+*.ibo-is-primary.ui-datepicker-close:disabled::before{border-left-color:#aebecd}.ibo-button-group>*+*.ibo-is-regular.ibo-is-secondary::before,.ui-dialog .ibo-button-group>*+*.ibo-is-secondary.ui-button::before,.ui-dialog .ibo-button-group>*+*.ui-button::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-datepicker-current::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-datepicker-close::before,.ibo-button-group>*+*.ibo-is-secondary.ui-datepicker-current::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-current.ui-button::before,.ibo-button-group>*+*.ui-datepicker-current::before,.ibo-button-group>*+*.ui-datepicker-current.ui-datepicker-close::before,.ibo-button-group>*+*.ibo-is-secondary.ui-datepicker-close::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-close.ui-button::before,.ibo-button-group>*+*.ui-datepicker-close.ui-datepicker-current::before,.ibo-button-group>*+*.ui-datepicker-close::before,.ui-dialog .ibo-button-group>*+*.ibo-is-regular.ui-button::before,.ibo-button-group>*+*.ibo-is-regular.ui-datepicker-current::before,.ibo-button-group>*+*.ibo-is-regular.ui-datepicker-close::before{border-left-color:#d5dde5}.ibo-button-group>*+*.ibo-is-regular.ibo-is-secondary:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-secondary.ui-button:hover::before,.ui-dialog .ibo-button-group>*+*.ui-button:hover::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-datepicker-current:hover::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-datepicker-close:hover::before,.ibo-button-group>*+*.ibo-is-secondary.ui-datepicker-current:hover::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-current.ui-button:hover::before,.ibo-button-group>*+*.ui-datepicker-current:hover::before,.ibo-button-group>*+*.ui-datepicker-current.ui-datepicker-close:hover::before,.ibo-button-group>*+*.ibo-is-secondary.ui-datepicker-close:hover::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-close.ui-button:hover::before,.ibo-button-group>*+*.ui-datepicker-close.ui-datepicker-current:hover::before,.ibo-button-group>*+*.ui-datepicker-close:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-regular.ui-button:hover::before,.ibo-button-group>*+*.ibo-is-regular.ui-datepicker-current:hover::before,.ibo-button-group>*+*.ibo-is-regular.ui-datepicker-close:hover::before{border-left-color:#d5dde5}.ibo-button-group>*+*.ibo-is-regular.ibo-is-secondary:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-secondary.ui-button:active::before,.ui-dialog .ibo-button-group>*+*.ui-button:active::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-datepicker-current:active::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-datepicker-close:active::before,.ibo-button-group>*+*.ibo-is-secondary.ui-datepicker-current:active::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-current.ui-button:active::before,.ibo-button-group>*+*.ui-datepicker-current:active::before,.ibo-button-group>*+*.ui-datepicker-current.ui-datepicker-close:active::before,.ibo-button-group>*+*.ibo-is-secondary.ui-datepicker-close:active::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-close.ui-button:active::before,.ibo-button-group>*+*.ui-datepicker-close.ui-datepicker-current:active::before,.ibo-button-group>*+*.ui-datepicker-close:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-regular.ui-button:active::before,.ibo-button-group>*+*.ibo-is-regular.ui-datepicker-current:active::before,.ibo-button-group>*+*.ibo-is-regular.ui-datepicker-close:active::before{border-left-color:#e1e7ec}.ibo-button-group>*+*.ibo-is-regular.ibo-is-secondary:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-secondary.ui-button:disabled::before,.ui-dialog .ibo-button-group>*+*.ui-button:disabled::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-datepicker-current:disabled::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-datepicker-close:disabled::before,.ibo-button-group>*+*.ibo-is-secondary.ui-datepicker-current:disabled::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-current.ui-button:disabled::before,.ibo-button-group>*+*.ui-datepicker-current:disabled::before,.ibo-button-group>*+*.ui-datepicker-current.ui-datepicker-close:disabled::before,.ibo-button-group>*+*.ibo-is-secondary.ui-datepicker-close:disabled::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-close.ui-button:disabled::before,.ibo-button-group>*+*.ui-datepicker-close.ui-datepicker-current:disabled::before,.ibo-button-group>*+*.ui-datepicker-close:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-regular.ui-button:disabled::before,.ibo-button-group>*+*.ibo-is-regular.ui-datepicker-current:disabled::before,.ibo-button-group>*+*.ibo-is-regular.ui-datepicker-close:disabled::before{border-left-color:#aebecd}.ibo-button-group>*+*.ibo-is-regular.ibo-is-danger::before,.ui-dialog .ibo-button-group>*+*.ibo-is-danger.ui-button::before,.ibo-button-group>*+*.ibo-is-danger.ui-datepicker-current::before,.ibo-button-group>*+*.ibo-is-danger.ui-datepicker-close::before{border-left-color:#9b2c2c}.ibo-button-group>*+*.ibo-is-regular.ibo-is-danger:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-danger.ui-button:hover::before,.ibo-button-group>*+*.ibo-is-danger.ui-datepicker-current:hover::before,.ibo-button-group>*+*.ibo-is-danger.ui-datepicker-close:hover::before{border-left-color:#9b2c2c}.ibo-button-group>*+*.ibo-is-regular.ibo-is-danger:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-danger.ui-button:active::before,.ibo-button-group>*+*.ibo-is-danger.ui-datepicker-current:active::before,.ibo-button-group>*+*.ibo-is-danger.ui-datepicker-close:active::before{border-left-color:#9b2c2c}.ibo-button-group>*+*.ibo-is-regular.ibo-is-danger:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-danger.ui-button:disabled::before,.ibo-button-group>*+*.ibo-is-danger.ui-datepicker-current:disabled::before,.ibo-button-group>*+*.ibo-is-danger.ui-datepicker-close:disabled::before{border-left-color:#aebecd}.ibo-button-group>*+*.ibo-is-regular.ibo-is-success::before,.ui-dialog .ibo-button-group>*+*.ibo-is-success.ui-button::before,.ibo-button-group>*+*.ibo-is-success.ui-datepicker-current::before,.ibo-button-group>*+*.ibo-is-success.ui-datepicker-close::before{border-left-color:#33691e}.ibo-button-group>*+*.ibo-is-regular.ibo-is-success:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-success.ui-button:hover::before,.ibo-button-group>*+*.ibo-is-success.ui-datepicker-current:hover::before,.ibo-button-group>*+*.ibo-is-success.ui-datepicker-close:hover::before{border-left-color:#33691e}.ibo-button-group>*+*.ibo-is-regular.ibo-is-success:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-success.ui-button:active::before,.ibo-button-group>*+*.ibo-is-success.ui-datepicker-current:active::before,.ibo-button-group>*+*.ibo-is-success.ui-datepicker-close:active::before{border-left-color:#33691e}.ibo-button-group>*+*.ibo-is-regular.ibo-is-success:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-success.ui-button:disabled::before,.ibo-button-group>*+*.ibo-is-success.ui-datepicker-current:disabled::before,.ibo-button-group>*+*.ibo-is-success.ui-datepicker-close:disabled::before{border-left-color:#aebecd}.ibo-button-group>*+*.ibo-is-regular.ibo-is-red::before,.ui-dialog .ibo-button-group>*+*.ibo-is-red.ui-button::before,.ibo-button-group>*+*.ibo-is-red.ui-datepicker-current::before,.ibo-button-group>*+*.ibo-is-red.ui-datepicker-close::before{border-left-color:#9b2c2c}.ibo-button-group>*+*.ibo-is-regular.ibo-is-red:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-red.ui-button:hover::before,.ibo-button-group>*+*.ibo-is-red.ui-datepicker-current:hover::before,.ibo-button-group>*+*.ibo-is-red.ui-datepicker-close:hover::before{border-left-color:#9b2c2c}.ibo-button-group>*+*.ibo-is-regular.ibo-is-red:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-red.ui-button:active::before,.ibo-button-group>*+*.ibo-is-red.ui-datepicker-current:active::before,.ibo-button-group>*+*.ibo-is-red.ui-datepicker-close:active::before{border-left-color:#9b2c2c}.ibo-button-group>*+*.ibo-is-regular.ibo-is-red:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-red.ui-button:disabled::before,.ibo-button-group>*+*.ibo-is-red.ui-datepicker-current:disabled::before,.ibo-button-group>*+*.ibo-is-red.ui-datepicker-close:disabled::before{border-left-color:#aebecd}.ibo-button-group>*+*.ibo-is-regular.ibo-is-green::before,.ui-dialog .ibo-button-group>*+*.ibo-is-green.ui-button::before,.ibo-button-group>*+*.ibo-is-green.ui-datepicker-current::before,.ibo-button-group>*+*.ibo-is-green.ui-datepicker-close::before{border-left-color:#33691e}.ibo-button-group>*+*.ibo-is-regular.ibo-is-green:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-green.ui-button:hover::before,.ibo-button-group>*+*.ibo-is-green.ui-datepicker-current:hover::before,.ibo-button-group>*+*.ibo-is-green.ui-datepicker-close:hover::before{border-left-color:#33691e}.ibo-button-group>*+*.ibo-is-regular.ibo-is-green:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-green.ui-button:active::before,.ibo-button-group>*+*.ibo-is-green.ui-datepicker-current:active::before,.ibo-button-group>*+*.ibo-is-green.ui-datepicker-close:active::before{border-left-color:#33691e}.ibo-button-group>*+*.ibo-is-regular.ibo-is-green:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-green.ui-button:disabled::before,.ibo-button-group>*+*.ibo-is-green.ui-datepicker-current:disabled::before,.ibo-button-group>*+*.ibo-is-green.ui-datepicker-close:disabled::before{border-left-color:#aebecd}.ibo-button-group>*+*.ibo-is-regular.ibo-is-cyan::before,.ui-dialog .ibo-button-group>*+*.ibo-is-cyan.ui-button::before,.ibo-button-group>*+*.ibo-is-cyan.ui-datepicker-current::before,.ibo-button-group>*+*.ibo-is-cyan.ui-datepicker-close::before{border-left-color:#006164}.ibo-button-group>*+*.ibo-is-regular.ibo-is-cyan:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-cyan.ui-button:hover::before,.ibo-button-group>*+*.ibo-is-cyan.ui-datepicker-current:hover::before,.ibo-button-group>*+*.ibo-is-cyan.ui-datepicker-close:hover::before{border-left-color:#006164}.ibo-button-group>*+*.ibo-is-regular.ibo-is-cyan:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-cyan.ui-button:active::before,.ibo-button-group>*+*.ibo-is-cyan.ui-datepicker-current:active::before,.ibo-button-group>*+*.ibo-is-cyan.ui-datepicker-close:active::before{border-left-color:#006164}.ibo-button-group>*+*.ibo-is-regular.ibo-is-cyan:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-cyan.ui-button:disabled::before,.ibo-button-group>*+*.ibo-is-cyan.ui-datepicker-current:disabled::before,.ibo-button-group>*+*.ibo-is-cyan.ui-datepicker-close:disabled::before{border-left-color:#aebecd}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-neutral::before,.ui-dialog .ibo-button-group>*+*.ibo-is-neutral.ui-button.ui-dialog-titlebar-close::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close::before,.ui-dialog .ibo-button-group>*+*.ibo-is-alternative.ui-button.ui-dialog-titlebar-close::before{border-left-color:#404b5a}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-neutral:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-neutral.ui-button.ui-dialog-titlebar-close:hover::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-alternative.ui-button.ui-dialog-titlebar-close:hover::before{border-left-color:#404b5a}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-neutral:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-neutral.ui-button.ui-dialog-titlebar-close:active::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-alternative.ui-button.ui-dialog-titlebar-close:active::before{border-left-color:#404b5a}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-neutral:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-neutral.ui-button.ui-dialog-titlebar-close:disabled::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-alternative.ui-button.ui-dialog-titlebar-close:disabled::before{border-left-color:#aebecd}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-primary::before,.ui-dialog .ibo-button-group>*+*.ibo-is-primary.ui-button.ui-dialog-titlebar-close::before{border-left-color:#00838f}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-primary:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-primary.ui-button.ui-dialog-titlebar-close:hover::before{border-left-color:#404b5a}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-primary:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-primary.ui-button.ui-dialog-titlebar-close:active::before{border-left-color:#404b5a}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-primary:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-primary.ui-button.ui-dialog-titlebar-close:disabled::before{border-left-color:#aebecd}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-secondary::before,.ui-dialog .ibo-button-group>*+*.ibo-is-secondary.ui-button.ui-dialog-titlebar-close::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close.ui-datepicker-current::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close.ui-datepicker-close::before,.ui-dialog .ibo-button-group>*+*.ibo-is-alternative.ui-button::before,.ibo-button-group>*+*.ibo-is-alternative.ui-datepicker-current::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-current.ui-button.ui-dialog-titlebar-close::before,.ibo-button-group>*+*.ibo-is-alternative.ui-datepicker-close::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-close.ui-button.ui-dialog-titlebar-close::before{border-left-color:#404b5a}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-secondary:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-secondary.ui-button.ui-dialog-titlebar-close:hover::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close:hover::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:hover::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-alternative.ui-button:hover::before,.ibo-button-group>*+*.ibo-is-alternative.ui-datepicker-current:hover::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:hover::before,.ibo-button-group>*+*.ibo-is-alternative.ui-datepicker-close:hover::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:hover::before{border-left-color:#404b5a}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-secondary:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-secondary.ui-button.ui-dialog-titlebar-close:active::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close:active::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:active::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-alternative.ui-button:active::before,.ibo-button-group>*+*.ibo-is-alternative.ui-datepicker-current:active::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:active::before,.ibo-button-group>*+*.ibo-is-alternative.ui-datepicker-close:active::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:active::before{border-left-color:#404b5a}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-secondary:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-secondary.ui-button.ui-dialog-titlebar-close:disabled::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close:disabled::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close.ui-datepicker-current:disabled::before,.ui-dialog .ibo-button-group>*+*.ui-button.ui-dialog-titlebar-close.ui-datepicker-close:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-alternative.ui-button:disabled::before,.ibo-button-group>*+*.ibo-is-alternative.ui-datepicker-current:disabled::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-current.ui-button.ui-dialog-titlebar-close:disabled::before,.ibo-button-group>*+*.ibo-is-alternative.ui-datepicker-close:disabled::before,.ui-dialog .ibo-button-group>*+*.ui-datepicker-close.ui-button.ui-dialog-titlebar-close:disabled::before{border-left-color:#aebecd}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-danger::before,.ui-dialog .ibo-button-group>*+*.ibo-is-danger.ui-button.ui-dialog-titlebar-close::before{border-left-color:#e53e3e}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-danger:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-danger.ui-button.ui-dialog-titlebar-close:hover::before{border-left-color:#9b2c2c}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-danger:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-danger.ui-button.ui-dialog-titlebar-close:active::before{border-left-color:#9b2c2c}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-danger:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-danger.ui-button.ui-dialog-titlebar-close:disabled::before{border-left-color:#aebecd}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-success::before,.ui-dialog .ibo-button-group>*+*.ibo-is-success.ui-button.ui-dialog-titlebar-close::before{border-left-color:#558b2f}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-success:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-success.ui-button.ui-dialog-titlebar-close:hover::before{border-left-color:#558b2f}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-success:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-success.ui-button.ui-dialog-titlebar-close:active::before{border-left-color:#558b2f}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-success:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-success.ui-button.ui-dialog-titlebar-close:disabled::before{border-left-color:#aebecd}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-red::before,.ui-dialog .ibo-button-group>*+*.ibo-is-red.ui-button.ui-dialog-titlebar-close::before{border-left-color:#e53e3e}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-red:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-red.ui-button.ui-dialog-titlebar-close:hover::before{border-left-color:#9b2c2c}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-red:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-red.ui-button.ui-dialog-titlebar-close:active::before{border-left-color:#9b2c2c}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-red:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-red.ui-button.ui-dialog-titlebar-close:disabled::before{border-left-color:#aebecd}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-green::before,.ui-dialog .ibo-button-group>*+*.ibo-is-green.ui-button.ui-dialog-titlebar-close::before{border-left-color:#558b2f}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-green:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-green.ui-button.ui-dialog-titlebar-close:hover::before{border-left-color:#558b2f}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-green:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-green.ui-button.ui-dialog-titlebar-close:active::before{border-left-color:#558b2f}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-green:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-green.ui-button.ui-dialog-titlebar-close:disabled::before{border-left-color:#aebecd}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-cyan::before,.ui-dialog .ibo-button-group>*+*.ibo-is-cyan.ui-button.ui-dialog-titlebar-close::before{border-left-color:#00838f}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-cyan:hover::before,.ui-dialog .ibo-button-group>*+*.ibo-is-cyan.ui-button.ui-dialog-titlebar-close:hover::before{border-left-color:#00838f}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-cyan:active::before,.ui-dialog .ibo-button-group>*+*.ibo-is-cyan.ui-button.ui-dialog-titlebar-close:active::before{border-left-color:#00838f}.ibo-button-group>*+*.ibo-is-alternative.ibo-is-cyan:disabled::before,.ui-dialog .ibo-button-group>*+*.ibo-is-cyan.ui-button.ui-dialog-titlebar-close:disabled::before{border-left-color:#aebecd}.ibo-breadcrumbs{position:relative;margin-right:32px}.ibo-breadcrumbs.ibo-is-overflowing{justify-content:right}.ibo-breadcrumbs *{display:flex;align-items:center}.ibo-breadcrumbs--item{color:#404b5a}.ibo-breadcrumbs--item:not(:last-child):hover .ibo-breadcrumbs--item-icon>*{opacity:1;filter:none}.ibo-breadcrumbs--item-icon{margin-right:8px;transition:all 0.1s linear}.ibo-breadcrumbs--item-icon>span{color:#929fb1;opacity:0.6}.ibo-breadcrumbs--item-icon>img{height:auto;max-width:16px;opacity:0.3;filter:grayscale(100%)}.ibo-breadcrumbs--item-label{display:inline;max-width:100px}.ibo-breadcrumbs--item:not(:last-child)::after,.ibo-breadcrumbs--previous-items-list-toggler:not(:last-child)::after{content:"";margin:0 12px;color:#aebecd}.ibo-breadcrumbs--previous-items-list-toggler{margin-right:24px;color:#6e7a8a !important}.ibo-breadcrumbs--previous-items-list-toggler:not(:last-child)::after{position:absolute;right:-24px}.ibo-breadcrumbs--previous-items-list{display:flex;flex-direction:column;align-items:stretch;position:fixed;top:37px;padding:8px 0;background-color:white}.ibo-breadcrumbs--previous-item{color:#404b5a;padding:12px 12px}.ibo-breadcrumbs--previous-item .ibo-breadcrumbs--item-label{max-width:200px}@keyframes ibo-quick-create--drawer--opening{from{top:-310px;box-shadow:none}to{top:100%;box-shadow:0 3px 6px rgba(0, 0, 0, 0.1), 0 10px 20px rgba(0, 0, 0, 0.15)}}.ibo-quick-create{position:relative}.ibo-quick-create.ibo-is-opened .ibo-quick-create--input,.ibo-quick-create.ibo-input-select-icon--menu .ibo-quick-create--input{width:245px}.ibo-quick-create.ibo-is-opened .ibo-quick-create--drawer,.ibo-quick-create.ibo-input-select-icon--menu .ibo-quick-create--drawer{animation-name:ibo-quick-create--drawer--opening;animation-delay:0.1s;animation-duration:0.2s;animation-direction:normal;animation-fill-mode:forwards}.ibo-quick-create--head{background-color:white}.ibo-quick-create--icon{color:#dd6c20;align-self:center;padding:0 16px}.ibo-quick-create--icon:hover{color:#c05621}.ibo-quick-create--icon:active{color:#9c4221}.ibo-quick-create--input{width:0;border:none;transition:all 0.2s ease-in-out}.ibo-quick-create--input.selectize-control.single{position:sticky;display:flex}.ibo-quick-create--input.selectize-control.single .selectize-input,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active{display:flex;background-color:transparent;background-image:none;border:none;box-shadow:none}.ibo-quick-create--input.selectize-control.single .selectize-input>input,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active>input{color:#404b5a;outline:none;border:none}.ibo-quick-create--input.selectize-control.single .selectize-input>input::placeholder,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active>input::placeholder{color:#929fb1}.ibo-quick-create--input.selectize-control.single .selectize-input>input:-ms-input-placeholder,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active>input:-ms-input-placeholder,.ibo-quick-create--input.selectize-control.single .selectize-input>input::-ms-input-placeholder,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active>input::-ms-input-placeholder{color:#929fb1}.ibo-quick-create--input.selectize-control.single .selectize-input>.item,.ibo-quick-create--input.selectize-control.single .selectize-input.input-active>.item{color:#404b5a;line-height:200%}.ibo-quick-create--input.selectize-control.single .selectize-dropdown{background-color:white;border:none;border-radius:0}.ibo-quick-create--drawer{z-index:-1;position:absolute;left:0;right:0;top:-310px;padding:16px 16px;background-color:white;box-shadow:none}.ibo-quick-create--compartment-title{margin-top:8px;margin-bottom:8px;padding-left:32px;overflow-x:hidden;color:#404b5a}.ibo-quick-create--compartment-title>span{position:relative}.ibo-quick-create--compartment-title>span::before,.ibo-quick-create--compartment-title>span::after{content:"";display:inline-block;position:absolute;top:50%;height:1px;width:600px;border-top:1px solid #404b5a}.ibo-quick-create--compartment-title>span::before{right:100%;margin-right:8px}.ibo-quick-create--compartment-title>span::after{left:100%;margin-left:8px}.ibo-quick-create--compartment-content{color:#212934}.ibo-quick-create--compartment-element{display:flex;align-items:center;padding:4px 8px;margin-left:-8px;margin-right:-8px;color:inherit}.ibo-quick-create--compartment-element-image{margin-right:8px;width:20px}.ibo-quick-create--compartment-results--container{position:static;width:100% !important;background:transparent;border:none;box-shadow:none}.ibo-quick-create--compartment-results--element{overflow:unset;max-height:unset}.ibo-quick-create--compartment-results--element>.option{padding:4px 8px;margin-left:-8px;margin-right:-8px;color:inherit}.ibo-quick-create--compartment-results--element>.option.active{background-color:#e1e7ec;border-radius:3px}.ibo-quick-create--compartment-results--element>.option:hover{cursor:pointer;color:#9c4221;text-decoration:none}.ibo-quick-create--compartment-results--element>.option .highlight{font-weight:bold}.ibo-quick-create--compartment--placeholder{align-items:center;display:flex;flex-direction:column}.ibo-quick-create--compartment--placeholder-image>svg{width:66%;height:inherit;margin:24px auto 16px auto;display:flex}.ibo-quick-create--compartment--placeholder-hint{text-align:justify;padding:0 8px;color:#6e7a8a}@keyframes ibo-global-search--drawer--opening{from{top:-310px;box-shadow:none}to{top:100%;box-shadow:0 3px 6px rgba(0, 0, 0, 0.1), 0 10px 20px rgba(0, 0, 0, 0.15)}}.ibo-global-search{position:relative}.ibo-global-search.ibo-is-opened .ibo-global-search--input,.ibo-global-search.ibo-input-select-icon--menu .ibo-global-search--input,.ibo-global-search.ibo-is-opened .ibo-global-search--input:hover,.ibo-global-search.ibo-is-opened .ibo-global-search--input:focus,.ibo-global-search.ibo-is-opened .ibo-global-search--input:active,.ibo-global-search.ibo-input-select-icon--menu .ibo-global-search--input:hover,.ibo-global-search.ibo-input-select-icon--menu .ibo-global-search--input:focus,.ibo-global-search.ibo-input-select-icon--menu .ibo-global-search--input:active{padding:8px 8px;width:245px}.ibo-global-search.ibo-is-opened .ibo-global-search--drawer,.ibo-global-search.ibo-input-select-icon--menu .ibo-global-search--drawer{animation-name:ibo-global-search--drawer--opening;animation-delay:0.1s;animation-duration:0.2s;animation-direction:normal;animation-fill-mode:forwards}.ibo-global-search--head{background-color:white}.ibo-global-search--icon{color:#dd6c20;align-self:center;padding:0 16px}.ibo-global-search--icon:hover{color:#c05621}.ibo-global-search--icon:active{color:#9c4221}.ibo-global-search--input,.ibo-global-search--input:hover,.ibo-global-search--input:focus,.ibo-global-search--input:active{padding:0;width:0;color:#404b5a;background-color:transparent;border:none;outline:none;transition:all 0.2s ease-in-out}.ibo-global-search--input::placeholder,.ibo-global-search--input:hover::placeholder,.ibo-global-search--input:focus::placeholder,.ibo-global-search--input:active::placeholder{color:#929fb1}.ibo-global-search--input:-ms-input-placeholder,.ibo-global-search--input:hover:-ms-input-placeholder,.ibo-global-search--input:focus:-ms-input-placeholder,.ibo-global-search--input:active:-ms-input-placeholder,.ibo-global-search--input::-ms-input-placeholder,.ibo-global-search--input:hover::-ms-input-placeholder,.ibo-global-search--input:focus::-ms-input-placeholder,.ibo-global-search--input:active::-ms-input-placeholder{color:#929fb1}.ibo-global-search--drawer{z-index:-1;position:absolute;left:0;right:0;top:-310px;padding:16px 16px;background-color:white;box-shadow:none}.ibo-global-search--compartment-title{margin-bottom:8px;padding-left:32px;overflow-x:hidden;color:#404b5a}.ibo-global-search--compartment-title>span{position:relative}.ibo-global-search--compartment-title>span::before,.ibo-global-search--compartment-title>span::after{content:"";display:inline-block;position:absolute;top:50%;height:1px;width:600px;border-top:1px solid #404b5a}.ibo-global-search--compartment-title>span::before{right:100%;margin-right:8px}.ibo-global-search--compartment-title>span::after{left:100%;margin-left:8px}.ibo-global-search--compartment-content{color:#212934}.ibo-global-search--compartment-element{display:flex;align-items:center;color:inherit}.ibo-global-search--compartment-element:not(:last-child){margin-bottom:8px}.ibo-global-search--compartment-element-image{margin-right:8px;width:20px}.ibo-global-search--compartment--placeholder{align-items:center;display:flex;flex-direction:column}.ibo-global-search--compartment--placeholder-image>svg{width:66%;height:inherit;margin:24px auto 16px auto;display:flex}.ibo-global-search--compartment--placeholder-hint{text-align:justify;padding:0 8px;color:#6e7a8a}.ibo-popover-menu,.ui-menu,.ui-multiselect-menu,.ibo-input-select-icon--menu,.graph_config .toolkit_menu.graph>ul>li ul{display:none;padding:0;background-color:white;border-radius:3px;flex-wrap:wrap;position:absolute}.ibo-popover-menu.ibo-is-opened,.ibo-is-opened.ui-menu,.ui-menu.ibo-input-select-icon--menu,.ibo-is-opened.ui-multiselect-menu,.ui-multiselect-menu.ibo-input-select-icon--menu,.ibo-is-opened.ibo-input-select-icon--menu,.ibo-input-select-icon--menu,.graph_config .toolkit_menu.graph>ul>li ul.ibo-is-opened,.graph_config .toolkit_menu.graph>ul>li ul.ibo-input-select-icon--menu,.ibo-popover-menu.ibo-input-select-icon--menu,.ibo-input-select-icon--menu.ui-menu,.ibo-input-select-icon--menu.ui-multiselect-menu{display:flex;flex-direction:column}.ibo-popover-menu--toggler-visual-hint{margin-left:0.5rem}.ibo-popover-menu--section,.ui-multiselect-checkboxes{display:flex;flex-direction:column;align-self:flex-start;margin:0 0;width:100%;white-space:nowrap;overflow:hidden}.ibo-popover-menu--section:first-child,.ui-multiselect-checkboxes:first-child{border-radius:3px 3px 0 0}.ibo-popover-menu--section:last-child,.ui-multiselect-checkboxes:last-child{border-radius:0 0 3px 3px}.ibo-popover-menu--item,.ui-menu-item,.ui-multiselect-checkboxes li,.ibo-input-select-icon--menu--item,.graph_config .toolkit_menu.graph>ul>li ul li{padding:12px 24px 12px 16px;color:#212934}.ibo-popover-menu--item a,.ui-menu-item a,.ui-multiselect-checkboxes li a,.ibo-input-select-icon--menu--item a,.graph_config .toolkit_menu.graph>ul>li ul li a{color:#212934}.ibo-popover-menu--item:hover,.ui-menu-item:hover,.ui-multiselect-checkboxes li:hover,.ibo-input-select-icon--menu--item:hover,.graph_config .toolkit_menu.graph>ul>li ul li:hover{background-color:#e1e7ec;color:inherit}.ibo-popover-menu--item.ibo-popover-menu--item-separator,.ibo-popover-menu--item-separator.ui-menu-item,.ui-menu-item.ui-autocomplete-category,.ui-multiselect-checkboxes li.ibo-popover-menu--item-separator,.ui-multiselect-checkboxes li.ui-autocomplete-category,.ibo-popover-menu--item-separator.ibo-input-select-icon--menu--item,.ibo-input-select-icon--menu--item.ui-autocomplete-category,.graph_config .toolkit_menu.graph>ul>li ul li.ibo-popover-menu--item-separator,.graph_config .toolkit_menu.graph>ul>li ul li.ui-autocomplete-category,.ibo-popover-menu--item.ui-autocomplete-category,.ui-autocomplete-category.ui-menu-item,.ui-autocomplete-category.ibo-input-select-icon--menu--item{padding:0;margin:0;background-color:#e1e7ec}.ibo-popover-menu--item--icon{padding-right:5px;color:#6e7a8a;font-size:1.33rem}#ibo-navigation-menu--notifications-menu{flex-flow:column;min-width:min(550px, 90vw);max-width:90vw}#ibo-navigation-menu--notifications-menu .ibo-navigation-menu--notifications--messages-section{overflow:auto}.ibo-navigation-menu--notifications--show-all-messages,.ibo-navigation-menu--notifications-dismiss-all,.ibo-navigation-menu--notifications-show-all-multiple{overflow-x:inherit;text-align:center;min-height:45px}.ibo-navigation-menu--notifications--item--image{max-width:20px;max-height:20px;margin:0 6px;border-radius:100%}.ibo-navigation-menu--notifications--item--image[src=""]{display:none}.ibo-navigation-menu--notifications--item--image:not([src=""])~.ibo-navigation-menu--notifications--item--image{display:none}.ibo-navigation-menu--notifications--item--bottom-text{display:flex;flex-direction:column;align-items:center;float:right;align-self:center;margin-left:auto;margin-right:auto}.ibo-navigation-menu--notifications--item--content{flex-grow:1;padding:0 14px;max-height:128px;overflow-y:auto;white-space:normal}.ibo-navigation-menu--notifications--item--content img{max-height:100px;padding:5px}.ibo-navigation-menu--notifications-item{display:flex;flex-direction:row;cursor:pointer}.ibo-navigation-menu--notifications--item--new-message-indicator{width:13px;height:13px;background-color:white;border:solid 2px #aebecd;border-radius:100%;margin-top:4px;flex-shrink:0}.ibo-navigation-menu--notifications--item--new-message-indicator.ibo-is-priority-1{background-color:#fce8e8;border:solid 2px #f56565}.ibo-navigation-menu--notifications--item--new-message-indicator.ibo-is-priority-2{background-color:floralwhite;border:solid 2px #ea7d1e}.ibo-navigation-menu--notifications--item--new-message-indicator.ibo-is-priority-3{background-color:#ebf8ff;border:solid 2px #429ae1}.ibo-navigation-menu--notifications--item--new-message-indicator.ibo-is-priority-4{background-color:white;border:solid 2px #aebecd}.ibo-navigation-menu--notifications-show-all-multiple~.ibo-popover-menu .ibo-navigation-menu--notifications--item--new-message-indicator,.ibo-navigation-menu--notifications-show-all-multiple~.ui-menu .ibo-navigation-menu--notifications--item--new-message-indicator,.ibo-navigation-menu--notifications-show-all-multiple~.ui-multiselect-menu .ibo-navigation-menu--notifications--item--new-message-indicator,.ibo-navigation-menu--notifications-show-all-multiple~.ibo-input-select-icon--menu .ibo-navigation-menu--notifications--item--new-message-indicator,.graph_config .toolkit_menu.graph>ul>li .ibo-navigation-menu--notifications-show-all-multiple~ul .ibo-navigation-menu--notifications--item--new-message-indicator{display:inline-block;margin-right:15px}.ibo-navigation-menu--notifications-dismiss-all--icon{margin:0 10px 0 0}.ibo-popover-menu--item--no-message{text-align:center}.ibo-popover-menu--item--no-message--image>svg{max-width:220px;height:inherit;padding:15px}.ibo-panel.ibo-has-sticky-header>.ibo-panel--header .ibo-panel--title,.ibo-panel.ibo-has-sticky-header>.ibo-object-summary--header .ibo-panel--title,.ibo-panel.ibo-has-sticky-header>.ibo-panel--header .ibo-panel--subtitle,.ibo-panel.ibo-has-sticky-header>.ibo-object-summary--header .ibo-panel--subtitle,.ibo-panel.ibo-has-sticky-header>.ibo-panel--header .ibo-panel--icon,.ibo-panel.ibo-has-sticky-header>.ibo-object-summary--header .ibo-panel--icon,.ibo-panel.ibo-has-sticky-header>.ibo-panel--header .ibo-panel--titles,.ibo-panel.ibo-has-sticky-header>.ibo-object-summary--header .ibo-panel--titles,.ibo-object-details.ibo-has-sticky-header>.ibo-panel--header .ibo-panel--header-left,.ibo-object-details.ibo-has-sticky-header>.ibo-object-summary--header .ibo-panel--header-left{transition:all 0.15s linear}.ibo-panel{--ibo-main-color: #929fb1;position:relative}.ibo-panel.ibo-has-icon>.ibo-panel--header .ibo-panel--titles,.ibo-panel.ibo-has-icon>.ibo-object-summary--header .ibo-panel--titles{padding-left:16px}.ibo-panel.ibo-has-icon.ibo-has-medallion-icon>.ibo-panel--header .ibo-panel--header-left,.ibo-panel.ibo-has-icon.ibo-has-medallion-icon>.ibo-object-summary--header .ibo-panel--header-left{position:relative;z-index:1;margin-left:16px}.ibo-panel.ibo-has-icon.ibo-has-medallion-icon>.ibo-panel--header .ibo-panel--header-left .ibo-panel--icon,.ibo-panel.ibo-has-icon.ibo-has-medallion-icon>.ibo-object-summary--header .ibo-panel--header-left .ibo-panel--icon{position:absolute;bottom:-24px;left:0;overflow:hidden;width:72px;height:72px;min-width:72px;min-height:72px;background-color:#f8f9fa;border:2px solid #90a4ae;border-radius:100%}.ibo-panel.ibo-has-icon.ibo-has-medallion-icon>.ibo-panel--header .ibo-panel--header-left .ibo-panel--titles,.ibo-panel.ibo-has-icon.ibo-has-medallion-icon>.ibo-object-summary--header .ibo-panel--header-left .ibo-panel--titles{padding-left:calc(72px + 16px)}.ibo-panel.ibo-is-selectable .ibo-panel--body::after{content:" ";background-color:transparent;cursor:pointer;position:absolute;display:flex;align-items:center;justify-content:center;height:100%;width:100%;z-index:3;font-size:7rem}.ibo-panel.ibo-is-selectable:hover .ibo-panel--body::after{content:"";color:#f8f9fa;background-color:rgba(146, 159, 177, 0.4);display:flex}.ibo-panel.ibo-is-selected .ibo-panel--body::after{content:"";color:#f8f9fa;background-color:rgba(33, 41, 52, 0.5);display:flex}.ibo-panel.ibo-is-selected:hover .ibo-panel--body::after{background-color:rgba(110, 122, 138, 0.5);display:flex}.ibo-panel--header,.ibo-object-summary--header{position:relative;z-index:2;display:flex;justify-content:space-between;align-items:flex-end;margin-bottom:4px}.ibo-panel--header-left{justify-content:left}.ibo-panel--icon{width:48px;height:48px;min-width:48px;min-height:48px}.ibo-panel--icon-img,.ibo-panel--icon-background{width:100%;height:100%;object-position:center;object-fit:contain;background-position:center;background-repeat:no-repeat;background-size:contain}.ibo-panel--icon-img--must-contain,.ibo-panel--icon-background--must-contain{object-fit:contain;background-size:contain}.ibo-panel--icon-img--must-cover,.ibo-panel--icon-background--must-cover{object-fit:cover;background-size:cover}.ibo-panel--icon-img--must-zoomout,.ibo-panel--icon-background--must-zoomout{width:66.67%;height:66.67%}.ibo-panel--title{display:inline-block;color:#212934;flex-grow:1}.ibo-panel--subtitle{display:flex;color:#404b5a}.ibo-panel--body{position:relative;z-index:1;padding:32px 16px 24px 16px;background-color:white;border:1px solid #ccd4db;border-radius:5px;overflow:hidden}.ibo-panel--body::before{position:absolute;top:0;left:0;display:block;background-color:var(--ibo-main-color);content:"";width:100%;height:8px;padding-bottom:8px}.ibo-panel.ibo-is-primary>.ibo-panel--body::before{background-color:#dd6c20}.ibo-panel.ibo-is-secondary>.ibo-panel--body::before,.ui-dialog .ibo-panel.ui-button>.ibo-panel--body::before,.ibo-panel.ui-datepicker-current>.ibo-panel--body::before,.ibo-panel.ui-datepicker-close>.ibo-panel--body::before{background-color:#929fb1}.ibo-panel.ibo-is-neutral>.ibo-panel--body::before,.ui-dialog .ibo-panel.ui-button.ui-dialog-titlebar-close>.ibo-panel--body::before{background-color:#929fb1}.ibo-panel.ibo-is-information>.ibo-panel--body::before{background-color:#3182ce}.ibo-panel.ibo-is-success>.ibo-panel--body::before{background-color:#7cb342}.ibo-panel.ibo-is-failure>.ibo-panel--body::before{background-color:#e53e3e}.ibo-panel.ibo-is-warning>.ibo-panel--body::before{background-color:#dd6c20}.ibo-panel.ibo-is-danger>.ibo-panel--body::before{background-color:#e53e3e}.ibo-panel.ibo-is-grey>.ibo-panel--body::before{background-color:#929fb1}.ibo-panel.ibo-is-blue-grey>.ibo-panel--body::before{background-color:#546e7a}.ibo-panel.ibo-is-blue>.ibo-panel--body::before{background-color:#2c5382}.ibo-panel.ibo-is-cyan>.ibo-panel--body::before{background-color:#00aac1}.ibo-panel.ibo-is-green>.ibo-panel--body::before{background-color:#7cb342}.ibo-panel.ibo-is-orange>.ibo-panel--body::before{background-color:#dd6c20}.ibo-panel.ibo-is-red>.ibo-panel--body::before{background-color:#e53e3e}.ibo-panel.ibo-is-pink>.ibo-panel--body::before{background-color:#d53f8c}.ibo-panel--collapsible-toggler{display:inline-block;margin-right:8px;font-size:1.5rem;color:#6e7a8a;cursor:pointer}.ibo-panel .ibo-panel--collapsible-toggler--opened{display:block}.ibo-panel .ibo-panel--collapsible-toggler--closed{display:none}.ibo-panel:not(.ibo-is-opened) .ibo-panel--collapsible-toggler--closed{display:block}.ibo-panel:not(.ibo-is-opened) .ibo-panel--collapsible-toggler--opened{display:none}.ibo-panel:not(.ibo-is-opened) .ibo-panel--body{display:none}.ibo-panel.ibo-has-sticky-header>.ibo-panel--header,.ibo-panel.ibo-has-sticky-header>.ibo-object-summary--header{position:sticky;top:0;border:transparent;transition-property:all, top, background-color;transition-duration:0.15s, 0s, 0s;transition-timing-function:linear}.ibo-panel.ibo-has-sticky-header>.ibo-panel--header.ibo-is-sticking,.ibo-panel.ibo-has-sticky-header>.ibo-is-sticking.ibo-object-summary--header{padding-top:4px;padding-bottom:4px;background-color:#f8f9fa;border:1px solid #ccd4db;align-items:center}.ibo-panel.ibo-has-sticky-header>.ibo-panel--header.ibo-is-sticking .ibo-panel--title,.ibo-panel.ibo-has-sticky-header>.ibo-is-sticking.ibo-object-summary--header .ibo-panel--title{font-size:1.17rem}.ibo-panel.ibo-has-sticky-header>.ibo-panel--header.ibo-is-sticking .ibo-panel--subtitle,.ibo-panel.ibo-has-sticky-header>.ibo-is-sticking.ibo-object-summary--header .ibo-panel--subtitle{font-size:1rem}.ibo-panel.ibo-has-sticky-header.ibo-has-icon.ibo-has-medallion-icon>.ibo-panel--header,.ibo-panel.ibo-has-sticky-header.ibo-has-icon.ibo-has-medallion-icon>.ibo-object-summary--header{}.ibo-panel.ibo-has-sticky-header.ibo-has-icon.ibo-has-medallion-icon>.ibo-panel--header.ibo-is-sticking .ibo-panel--icon,.ibo-panel.ibo-has-sticky-header.ibo-has-icon.ibo-has-medallion-icon>.ibo-is-sticking.ibo-object-summary--header .ibo-panel--icon{bottom:-12px;width:48px;height:48px;min-width:48px;min-height:48px;border:1px solid #ccd4db}.ibo-panel.ibo-has-sticky-header.ibo-has-icon.ibo-has-medallion-icon>.ibo-panel--header.ibo-is-sticking .ibo-panel--titles,.ibo-panel.ibo-has-sticky-header.ibo-has-icon.ibo-has-medallion-icon>.ibo-is-sticking.ibo-object-summary--header .ibo-panel--titles{padding-left:calc(48px + 16px)}.ibo-collapsible-section--header{display:flex;align-items:stretch}.ibo-collapsible-section.ibo-is-opened .ibo-collapsible-section--minimize-button,.ibo-collapsible-section.ibo-input-select-icon--menu .ibo-collapsible-section--minimize-button{display:block}.ibo-collapsible-section.ibo-is-opened .ibo-collapsible-section--maximize-button,.ibo-collapsible-section.ibo-input-select-icon--menu .ibo-collapsible-section--maximize-button{display:none}.ibo-collapsible-section:not(.ibo-is-opened) .ibo-collapsible-section--minimize-button{display:none}.ibo-collapsible-section:not(.ibo-is-opened) .ibo-collapsible-section--maximize-button{display:block}.ibo-collapsible-section:not(.ibo-is-opened) .ibo-collapsible-section--body{display:none}.ibo-collapsible-section .ibo-collapsible-section--header{cursor:pointer}.ibo-collapsible-section .ibo-collapsible-section--header:hover i{opacity:0.8}.ibo-collapsible-section .ibo-collapsible-section--header .ibo-collapsible-section--action-button{align-self:center}.ibo-collapsible-section .ibo-collapsible-section--header .ibo-collapsible-section--action-button.ibo-collapsible-section--maximize-button,.ibo-collapsible-section .ibo-collapsible-section--header .ibo-collapsible-section--action-button.ibo-collapsible-section--minimize-button{color:#6e7a8a;margin-right:8px}.ibo-collapsible-section .ibo-collapsible-section--header .ibo-collapsible-section--title{color:#212934;flex-grow:1}.ibo-collapsible-section .ibo-collapsible-section--body{position:relative;padding:24px 16px 16px;background-color:white;border:solid 1px #ccd4db;border-radius:5px;overflow:hidden}.ibo-modal{display:flex;flex-direction:column;max-height:90vh !important;max-width:90vw !important}.ibo-modal.ibo-is-extra-small{height:calc(min(20vh, 150px)) !important;width:calc(min(20vw, 200px)) !important}.ibo-modal.ibo-is-small{height:calc(min(60vh, 400px)) !important;width:calc(min(60vw, 800px)) !important}.ibo-modal.ibo-is-medium{height:calc(min(75vh, 600px)) !important;width:calc(min(75vw, 1200px)) !important}.ibo-modal.ibo-is-large{height:calc(min(90vh, 900px)) !important;width:calc(min(90vw, 1800px)) !important}.ibo-modal-option--do-not-show-again{margin-top:16px}.ibo-modal-option--do-not-show-again .ibo-modal-option--do-not-show-again--checkbox{height:auto;display:inline-block;width:auto}.ibo-modal.ibo-is-informative{align-items:center;min-width:384px;min-height:24px !important}.ibo-modal.ibo-is-informative::before{display:block;position:absolute;top:0;left:0;content:"";width:4px;height:100%}.ibo-modal.ibo-is-informative.ibo-is-error::before{background-color:#e53e3e}.ibo-modal.ibo-is-informative.ibo-is-warning::before{background-color:#dd6c20}.ibo-modal.ibo-is-informative.ibo-is-information::before{background-color:#3182ce}.ibo-modal.ibo-is-informative.ibo-is-success::before{background-color:#7cb342}.ibo-dashlet{position:relative;width:calc(100% - 24px);margin:calc(24px / 2) calc(24px / 2)}.ibo-dashlet.dashlet-selected{position:relative}.ibo-dashlet--is-inline{width:auto}.ibo-dashlet-blocker{position:absolute;z-index:9;top:0;left:0;width:100%;height:100%;cursor:not-allowed}:root{--ibo-dashlet-badge--min-width: 200px;--ibo-dashlet-badge--padding-x: 16px;--ibo-dashlet-badge--padding-y: 16px;--ibo-dashlet-badge--background-color: white;--ibo-dashlet-badge--border: 1px solid #ccd4db;--ibo-dashlet-badge--border-radius: 5px}.ibo-dashlet-badge{max-width:350px;flex-basis:200px;flex-grow:1;flex-shrink:1;padding:16px 16px;background-color:white;border:1px solid #ccd4db;border-radius:5px}.ibo-dashlet-badge--body{display:flex;justify-items:left;align-items:center}.ibo-dashlet-badge--icon-container{margin-right:16px}.ibo-dashlet-badge--icon{width:48px;min-width:48px;max-height:48px}.ibo-dashlet-badge--actions{flex-grow:1;overflow-x:hidden}.ibo-dashlet-badge--action-list{color:inherit}.ibo-dashlet-badge--action-list-count{margin-right:8px}.ibo-dashlet-badge--action-list-label{display:inline-block}.ibo-dashlet-badge--action-create-icon{margin-right:8px}.ibo-dashlet-badge--body--tooltip-title{margin-bottom:16px}.ibo-dashlet-header-static{padding:16px 16px 0 16px;overflow-x:hidden}.ibo-dashlet-header-static--body{position:relative;display:inline-flex;justify-items:left;align-items:center;margin-left:48px;color:#212934}.ibo-dashlet-header-static--body::before,.ibo-dashlet-header-static--body::after{content:"";position:absolute;top:50%;width:10000px;height:1px;border-bottom:2px solid #ccd4db}.ibo-dashlet-header-static--body::before{right:calc(100% + 16px)}.ibo-dashlet-header-static--body::after{left:calc(100% + 16px)}.ibo-dashlet-header-static--icon-container{margin-right:16px}.ibo-dashlet-header-static--icon{width:48px;min-width:48px;max-height:48px}.ibo-dashlet-header-dynamic--container{display:flex;flex-wrap:wrap}.ibo-dashlet-header-dynamic--count{margin-right:10px}.ibo-input,.ui-autocomplete-input,.ui-multiselect,.dataTables_length select,.ui_tpicker_hour_slider>select,.ui_tpicker_minute_slider>select,.ui_tpicker_second_slider>select,select.ibo-input-select-placeholder,.ibo-datatableconfig--attributes-panel--per-page--input,.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content input[type="text"],.search_form_handler .sf_filter .sff_input_wrapper input[type="text"]{height:30px;width:100%;background-color:white;color:#212934;padding:0 10px;border:1px solid #aebecd;border-radius:3px}.ibo-input:focus,.ui-autocomplete-input:focus,.ui-multiselect:focus,.dataTables_length select:focus,.ui_tpicker_hour_slider>select:focus,.ui_tpicker_minute_slider>select:focus,.ui_tpicker_second_slider>select:focus,select.ibo-input-select-placeholder:focus,.ibo-datatableconfig--attributes-panel--per-page--input:focus,.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content input[type="text"]:focus,.search_form_handler .sf_filter .sff_input_wrapper input[type="text"]:focus{border-color:#dd6c20}.ibo-input:disabled,.ui-autocomplete-input:disabled,.ui-multiselect:disabled,.dataTables_length select:disabled,.ui_tpicker_hour_slider>select:disabled,.ui_tpicker_minute_slider>select:disabled,.ui_tpicker_second_slider>select:disabled,select.ibo-input-select-placeholder:disabled,.ibo-datatableconfig--attributes-panel--per-page--input:disabled,.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content input[type="text"]:disabled,.search_form_handler .sf_filter .sff_input_wrapper input[type="text"]:disabled{background-color:#d5dde5;color:#929fb1}.ibo-input::placeholder,.ui-autocomplete-input::placeholder,.ui-multiselect::placeholder,.dataTables_length select::placeholder,.ui_tpicker_hour_slider>select::placeholder,.ui_tpicker_minute_slider>select::placeholder,.ui_tpicker_second_slider>select::placeholder,select.ibo-input-select-placeholder::placeholder,.ibo-datatableconfig--attributes-panel--per-page--input::placeholder,.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content input[type="text"]::placeholder,.search_form_handler .sf_filter .sff_input_wrapper input[type="text"]::placeholder{color:#929fb1}textarea.ibo-input,textarea.ui-autocomplete-input,textarea.ui-multiselect,textarea.ibo-datatableconfig--attributes-panel--per-page--input{height:unset}.ibo-input-wrapper.is-error .ibo-input,.is-error.ui_tpicker_hour_slider .ibo-input,.is-error.ui_tpicker_hour_slider .ui-autocomplete-input,.is-error.ui_tpicker_hour_slider .ui-multiselect,.is-error.ui_tpicker_hour_slider .dataTables_length select,.dataTables_length .is-error.ui_tpicker_hour_slider select,.is-error.ui_tpicker_hour_slider .ui_tpicker_hour_slider>select,.is-error.ui_tpicker_hour_slider .ui_tpicker_minute_slider>select,.is-error.ui_tpicker_hour_slider .ui_tpicker_second_slider>select,.is-error.ui_tpicker_hour_slider select.ibo-input-select-placeholder,.is-error.ui_tpicker_hour_slider .ibo-datatableconfig--attributes-panel--per-page--input,.is-error.ui_tpicker_hour_slider .search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content input[type="text"],.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content .is-error.ui_tpicker_hour_slider input[type="text"],.is-error.ui_tpicker_hour_slider .search_form_handler .sf_filter .sff_input_wrapper input[type="text"],.search_form_handler .sf_filter .sff_input_wrapper .is-error.ui_tpicker_hour_slider input[type="text"],.is-error.ui_tpicker_minute_slider .ibo-input,.is-error.ui_tpicker_minute_slider .ui-autocomplete-input,.is-error.ui_tpicker_minute_slider .ui-multiselect,.is-error.ui_tpicker_minute_slider .dataTables_length select,.dataTables_length .is-error.ui_tpicker_minute_slider select,.is-error.ui_tpicker_minute_slider .ui_tpicker_hour_slider>select,.is-error.ui_tpicker_minute_slider .ui_tpicker_minute_slider>select,.is-error.ui_tpicker_minute_slider .ui_tpicker_second_slider>select,.is-error.ui_tpicker_minute_slider select.ibo-input-select-placeholder,.is-error.ui_tpicker_minute_slider .ibo-datatableconfig--attributes-panel--per-page--input,.is-error.ui_tpicker_minute_slider .search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content input[type="text"],.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content .is-error.ui_tpicker_minute_slider input[type="text"],.is-error.ui_tpicker_minute_slider .search_form_handler .sf_filter .sff_input_wrapper input[type="text"],.search_form_handler .sf_filter .sff_input_wrapper .is-error.ui_tpicker_minute_slider input[type="text"],.is-error.ui_tpicker_second_slider .ibo-input,.is-error.ui_tpicker_second_slider .ui-autocomplete-input,.is-error.ui_tpicker_second_slider .ui-multiselect,.is-error.ui_tpicker_second_slider .dataTables_length select,.dataTables_length .is-error.ui_tpicker_second_slider select,.is-error.ui_tpicker_second_slider .ui_tpicker_hour_slider>select,.is-error.ui_tpicker_second_slider .ui_tpicker_minute_slider>select,.is-error.ui_tpicker_second_slider .ui_tpicker_second_slider>select,.is-error.ui_tpicker_second_slider select.ibo-input-select-placeholder,.is-error.ui_tpicker_second_slider .ibo-datatableconfig--attributes-panel--per-page--input,.is-error.ui_tpicker_second_slider .search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content input[type="text"],.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content .is-error.ui_tpicker_second_slider input[type="text"],.is-error.ui_tpicker_second_slider .search_form_handler .sf_filter .sff_input_wrapper input[type="text"],.search_form_handler .sf_filter .sff_input_wrapper .is-error.ui_tpicker_second_slider input[type="text"],.ibo-input-wrapper.is-error .ui-autocomplete-input,.ibo-input-wrapper.is-error .ui-multiselect,.ibo-input-wrapper.is-error .dataTables_length select,.dataTables_length .ibo-input-wrapper.is-error select,.ibo-input-wrapper.is-error .ui_tpicker_hour_slider>select,.ibo-input-wrapper.is-error .ui_tpicker_minute_slider>select,.ibo-input-wrapper.is-error .ui_tpicker_second_slider>select,.ibo-input-wrapper.is-error select.ibo-input-select-placeholder,.ibo-input-wrapper.is-error .ibo-datatableconfig--attributes-panel--per-page--input,.ibo-input-wrapper.is-error .search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content input[type="text"],.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content .ibo-input-wrapper.is-error input[type="text"],.ibo-input-wrapper.is-error .search_form_handler .sf_filter .sff_input_wrapper input[type="text"],.search_form_handler .sf_filter .sff_input_wrapper .ibo-input-wrapper.is-error input[type="text"],.ibo-input-wrapper.is-error .ibo-input-vanilla,.is-error.ui_tpicker_hour_slider .ibo-input-vanilla,.is-error.ui_tpicker_minute_slider .ibo-input-vanilla,.is-error.ui_tpicker_second_slider .ibo-input-vanilla,.ibo-input-wrapper.is-error .ck-editor,.is-error.ui_tpicker_hour_slider .ck-editor,.is-error.ui_tpicker_minute_slider .ck-editor,.is-error.ui_tpicker_second_slider .ck-editor,.ibo-input-wrapper.is-error textarea,.is-error.ui_tpicker_hour_slider textarea,.is-error.ui_tpicker_minute_slider textarea,.is-error.ui_tpicker_second_slider textarea,.ibo-input-field-wrapper.is-error .ibo-input,.ibo-input-field-wrapper.is-error .ui-autocomplete-input,.ibo-input-field-wrapper.is-error .ui-multiselect,.ibo-input-field-wrapper.is-error .dataTables_length select,.dataTables_length .ibo-input-field-wrapper.is-error select,.ibo-input-field-wrapper.is-error .ui_tpicker_hour_slider>select,.ibo-input-field-wrapper.is-error .ui_tpicker_minute_slider>select,.ibo-input-field-wrapper.is-error .ui_tpicker_second_slider>select,.ibo-input-field-wrapper.is-error select.ibo-input-select-placeholder,.ibo-input-field-wrapper.is-error .ibo-datatableconfig--attributes-panel--per-page--input,.ibo-input-field-wrapper.is-error .search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content input[type="text"],.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content .ibo-input-field-wrapper.is-error input[type="text"],.ibo-input-field-wrapper.is-error .search_form_handler .sf_filter .sff_input_wrapper input[type="text"],.search_form_handler .sf_filter .sff_input_wrapper .ibo-input-field-wrapper.is-error input[type="text"],.ibo-input-field-wrapper.is-error .ibo-input-vanilla,.ibo-input-field-wrapper.is-error .ck-editor,.ibo-input-field-wrapper.is-error textarea{border-color:#e53e3e}.ibo-input-wrapper.is-error .ibo-input-vanilla input,.is-error.ui_tpicker_hour_slider .ibo-input-vanilla input,.is-error.ui_tpicker_minute_slider .ibo-input-vanilla input,.is-error.ui_tpicker_second_slider .ibo-input-vanilla input,.ibo-input-field-wrapper.is-error .ibo-input-vanilla input{border:0;background-color:rgba(255, 255, 255, 0)}input.ibo-input-vanilla{width:unset;display:initial}.ibo-input-wrapper--with-buttons,.ibo-input-select-wrapper--with-buttons{position:relative;display:flex}.ibo-field-validation{color:#c53030}.file-input{display:block;position:relative}.ibo-input--label-right{margin-right:4px;display:inline}.ibo-input--label-left{margin-left:4px;display:inline}.disabled{background-color:#d5dde5}.ibo-input-checkbox{height:16px;width:auto}.ibo-input-date-wrapper{position:relative}.ibo-input-date{display:inline-block;width:100%}.ibo-input-date+button{position:absolute;display:inline-block;margin-left:-20px;margin-top:5px;padding:0;background-color:transparent;color:#404b5a;border:none}.ibo-input-datetime-wrapper{position:relative}.ibo-input-datetime{display:inline-block;width:100%}.ibo-input-datetime--action-button{position:absolute;display:inline-block;margin-left:-20px;margin-top:5px;padding:0;color:#404b5a}.ui_tpicker_hour_slider>select,.ui_tpicker_minute_slider>select,.ui_tpicker_second_slider>select{width:auto;padding-right:18px}.ibo-input-duration{display:inline-block;width:unset;text-align:right}.ibo-input-image{display:flex;justify-content:flex-start;align-items:flex-start}.ibo-input-image--image-view{position:relative;overflow:hidden;min-height:96px;background-color:#e1e7ec;border-radius:5px}.ibo-input-image--image-view img[src=""],.ibo-input-image--image-view img[src="null"]{visibility:hidden}.ibo-input-image--image-view input[type="file"]{position:absolute;top:0;bottom:0;left:0;right:0;width:100%;opacity:0}.ibo-input-image--edit-buttons{display:flex;flex-direction:column;margin-left:0.5rem}.ibo-input-image--edit-buttons .ibo-button+.ibo-button,.ibo-input-image--edit-buttons .ui-dialog .ui-button+.ibo-button,.ibo-input-image--edit-buttons .ui-dialog .ui-dialog .ui-button+.ui-button,.ui-dialog .ibo-input-image--edit-buttons .ui-dialog .ui-button+.ui-button,.ibo-input-image--edit-buttons .ui-dialog .ui-button+.ui-datepicker-current,.ibo-input-image--edit-buttons .ui-dialog .ui-button+.ui-datepicker-close,.ui-dialog .ibo-input-image--edit-buttons .ui-button+.ibo-button,.ibo-input-image--edit-buttons .ui-datepicker-current+.ibo-button,.ibo-input-image--edit-buttons .ui-dialog .ui-datepicker-current+.ui-button,.ui-dialog .ibo-input-image--edit-buttons .ui-datepicker-current+.ui-button,.ibo-input-image--edit-buttons .ui-datepicker-current+.ui-datepicker-current,.ibo-input-image--edit-buttons .ui-datepicker-current+.ui-datepicker-close,.ibo-input-image--edit-buttons .ui-datepicker-close+.ibo-button,.ibo-input-image--edit-buttons .ui-dialog .ui-datepicker-close+.ui-button,.ui-dialog .ibo-input-image--edit-buttons .ui-datepicker-close+.ui-button,.ibo-input-image--edit-buttons .ui-datepicker-close+.ui-datepicker-current,.ibo-input-image--edit-buttons .ui-datepicker-close+.ui-datepicker-close,.ibo-input-image--edit-buttons .ui-dialog .ibo-button+.ui-button,.ui-dialog .ibo-input-image--edit-buttons .ibo-button+.ui-button,.ibo-input-image--edit-buttons .ibo-button+.ui-datepicker-current,.ibo-input-image--edit-buttons .ibo-button+.ui-datepicker-close{margin-top:0.5rem;margin-left:0}.ibo-input-richtext-placeholder{height:192px;width:100%;visibility:hidden}.ibo-input-select,.ui-multiselect,.ui_tpicker_hour_slider>select,.ui_tpicker_minute_slider>select,.ui_tpicker_second_slider>select,select.ibo-input-select-placeholder{display:inline-flex;min-width:50px;appearance:none}.ibo-input-select.ibo-input-selectize,.ibo-input-selectize.ui-multiselect,.ui_tpicker_hour_slider>select.ibo-input-selectize,.ui_tpicker_minute_slider>select.ibo-input-selectize,.ui_tpicker_second_slider>select.ibo-input-selectize,select.ibo-input-selectize.ibo-input-select-placeholder{padding-right:0;padding-left:0;min-width:150px !important}.ibo-input-select.ibo-input-selectize input,.ibo-input-selectize.ui-multiselect input,.ui_tpicker_hour_slider>select.ibo-input-selectize input,.ui_tpicker_minute_slider>select.ibo-input-selectize input,.ui_tpicker_second_slider>select.ibo-input-selectize input,select.ibo-input-selectize.ibo-input-select-placeholder input{border-width:0;color:inherit;border-color:white;padding-left:10px}.ibo-input-select.ibo-input-selectize>[data-value],.ibo-input-selectize.ui-multiselect>[data-value],.ui_tpicker_hour_slider>select.ibo-input-selectize>[data-value],.ui_tpicker_minute_slider>select.ibo-input-selectize>[data-value],.ui_tpicker_second_slider>select.ibo-input-selectize>[data-value],select.ibo-input-selectize.ibo-input-select-placeholder>[data-value]{height:100%;line-height:30px;padding-left:10px}.ibo-input-select[size],.ui-multiselect[size],.ui_tpicker_hour_slider>select[size],.ui_tpicker_minute_slider>select[size],.ui_tpicker_second_slider>select[size],select.ibo-input-select-placeholder[size]{height:auto}.ibo-input-select[multiple],.ui-multiselect[multiple],.ui_tpicker_hour_slider>select[multiple],.ui_tpicker_minute_slider>select[multiple],.ui_tpicker_second_slider>select[multiple],select.ibo-input-select-placeholder[multiple]{padding-left:unset;padding-right:unset}.ibo-input-select[multiple] option,.ui-multiselect[multiple] option,.ui_tpicker_hour_slider>select[multiple] option,.ui_tpicker_minute_slider>select[multiple] option,.ui_tpicker_second_slider>select[multiple] option,select.ibo-input-select-placeholder[multiple] option{padding:4px 10px}.ibo-input-select-autocomplete{min-width:150px !important;text-overflow:ellipsis}.ibo-input-selectize{min-width:150px !important}.ibo-input-selectize>div{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ibo-input-selectize>input{background-color:unset;border:unset}.ibo-input-selectize>input:focus{outline:none !important}.ibo-input-selectize.input-active{border:1px solid #dd6c20}.ibo-input-select-wrapper,.ui_tpicker_hour_slider,.ui_tpicker_minute_slider,.ui_tpicker_second_slider{position:relative}.ibo-input-select-wrapper--with-buttons .selectize-control{display:grid;width:100%}.ibo-input-select-wrapper::after,.ui_tpicker_hour_slider::after,.ui_tpicker_minute_slider::after,.ui_tpicker_second_slider::after{position:absolute;z-index:1;content:"";font-family:"Font Awesome 5 Free";font-weight:600;height:28px;margin-left:-16px;margin-top:1px;padding-top:3px;background-color:inherit;color:#212934;pointer-events:none}.ibo-input-select-container{display:flex}.ibo-input-select-wrapper--with-buttons:not(.ibo-input-select-autocomplete-wrapper)::after{position:absolute;z-index:1;content:"";font-family:"Font Awesome 5 Free";font-weight:600;cursor:pointer;right:8px;height:28px;margin-left:-16px;margin-top:1px;padding-top:3px;background-color:inherit;color:#212934;pointer-events:none}.ibo-input-select--action-buttons{position:absolute;z-index:1;display:flex;height:28px;margin-top:0;margin-right:3px;font-size:1rem;background-color:inherit;color:#404b5a;padding:0 2px;text-align:right;bottom:0;top:0;right:0}.ibo-input-select-wrapper .ibo-input-select--action-buttons,.ui_tpicker_hour_slider .ibo-input-select--action-buttons,.ui_tpicker_minute_slider .ibo-input-select--action-buttons,.ui_tpicker_second_slider .ibo-input-select--action-buttons{margin-right:20px}.ibo-input-select--action-button{display:flex;align-items:center;padding-left:6px;padding-right:2px;float:right}.selectize-dropdown.ui-autocomplete,.selectize-dropdown.set-dropdown,.selectize-dropdown.plugin-custom_itop{z-index:2000;max-height:50vh;max-width:50em;overflow-y:auto}.selectize-dropdown-content{max-height:calc(50vh - 4px)}.selectize-dropdown.ui-menu .ui-state-active{margin:unset;background-color:#ebf8ff;color:#404b5a}.ibo-input-select--autocomplete-item,.ibo-input-select--notification-item{display:flex;justify-content:left;align-items:center}.ibo-input-select--autocomplete-item-image{width:30px;height:30px;min-width:30px;min-height:30px;background-position:center center;background-size:100%;border-radius:100%;margin-right:0.7rem;background-color:#ebf8ff;border:1px solid #929fb1}.ibo-input-select--autocomplete-item-image.ibo-is-not-medallion{border:unset;border-radius:0;background-color:unset}.ibo-input-select-icon{display:inline-flex;text-align:left}.ibo-input-select-icon>img{max-height:100%;max-width:100%;padding-right:4px}.ibo-input-select-icon>span{overflow:hidden}.ibo-input-select-icon--menu{position:absolute;z-index:21;max-height:300px;overflow-x:hidden;overflow-y:auto;flex-wrap:nowrap}.ibo-input-select-icon--menu--item>*{width:100%;white-space:nowrap;overflow-x:hidden;text-overflow:ellipsis}.ibo-input-select-icon--menu--item>*>.ibo-input-select-icon--menu--icon{max-width:100%;max-height:100%;margin-right:10px}.ibo-input-one-way-password-wrapper>*:not(first-child){margin-top:6px}.ibo-input-set{flex-wrap:wrap;height:auto;min-height:30px}.ibo-input-set>input{height:auto}.ibo-input-set .item[data-value]>.remove{font-size:18px;padding-top:0.15em;border-left:none}.attribute-set .attribute-set-item,.selectize-control.multi .selectize-input.ibo-input-set .attribute-set-item,.selectize-control.multi .ibo-quick-create--input.selectize-control.single .ibo-input-set.selectize-input.input-active .attribute-set-item,.ibo-quick-create--input.selectize-control.single .selectize-control.multi .ibo-input-set.selectize-input.input-active .attribute-set-item{display:inline-flex;margin-top:1px;margin-right:0;margin-bottom:1px;padding:4px 6px;max-width:360px;background:white none;border:none;border-radius:3px;box-shadow:0 1px 1px rgba(0, 0, 0, 0.15), 0 0 1px 1px rgba(241, 241, 241, 0.7);color:#212934;text-shadow:none}.attribute-set .attribute-set-item:not(:first-child),.selectize-control.multi .selectize-input.ibo-input-set .attribute-set-item:not(:first-child),.selectize-control.multi .ibo-quick-create--input.selectize-control.single .ibo-input-set.selectize-input.input-active .attribute-set-item:not(:first-child),.ibo-quick-create--input.selectize-control.single .selectize-control.multi .ibo-input-set.selectize-input.input-active .attribute-set-item:not(:first-child){margin-left:3px}.attribute-set.history-added .attribute-set-item{font-weight:bold}.attribute-set.history-removed .attribute-set-item{text-decoration:line-through;font-style:italic}.selectize-control.multi .selectize-input.ibo-input-set,.selectize-control.multi .ibo-quick-create--input.selectize-control.single .ibo-input-set.selectize-input.input-active,.ibo-quick-create--input.selectize-control.single .selectize-control.multi .ibo-input-set.selectize-input.input-active{padding:0 8px}.ibo-input-text,textarea{width:100%;min-height:12rem;padding:10px 12px}.ibo-input-text.ibo-is-code,textarea.ibo-is-code{background-color:white}.ibo-input-text--export{width:100%;min-height:15em}.ibo-toggler--wrapper{position:relative;display:inline-block;width:36px;height:20px;vertical-align:baseline}.ibo-toggler--wrapper .ibo-toggler{display:none}.ibo-toggler--slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;border-radius:16px;background-color:#929fb1;transition:0.4s}.ibo-toggler--slider:before{content:"";position:absolute;left:3px;bottom:3px;height:15px;width:15px;border-radius:100%;background-color:#f8f9fa;transition:0.4s}.ibo-toggler--wrapper input:checked+.ibo-toggler--slider{background-color:#dd6c20}.ibo-toggler--wrapper input:disabled+.ibo-toggler--slider{background-color:#e1e7ec}.ibo-toggler--wrapper input:checked:disabled+.ibo-toggler--slider{background-color:#feebc8}input:focus+.ibo-toggler--slider{box-shadow:0 0 1px #dd6c20}input:checked+.ibo-toggler--slider:before{transform:translateX(14.5px)}label~.ibo-toggler--wrapper{margin-left:4px}.ibo-pill.ibo-is-new{color:#2a4265;background-color:#ebf8ff}.ibo-pill.ibo-is-neutral,.ui-dialog .ibo-pill.ui-button.ui-dialog-titlebar-close{color:#2a4265;background-color:#ebf8ff}.ibo-pill.ibo-is-waiting{color:#9c4221;background-color:floralwhite}.ibo-pill.ibo-is-success{color:#33691e;background-color:#dcedc8}.ibo-pill.ibo-is-failure{color:#9b2c2c;background-color:#fce8e8}.ibo-pill.ibo-is-frozen{color:#6e7a8a;background-color:#f8f9fa}.ibo-pill.ibo-is-active{color:#33691e;background-color:#dcedc8}.ibo-pill.ibo-is-inactive{color:#9c4221;background-color:floralwhite}.ibo-pill{--ibo-main-color--100: #ebf8ff;--ibo-main-color--900: #2a4265;max-width:240px;margin-top:4px;margin-bottom:4px;padding:6px 10px;border-radius:3px;color:var(--ibo-main-color--900);background-color:var(--ibo-main-color--100)}.ibo-pill:hover,.ibo-pill:active{color:inherit}.ibo-prop--apply{width:calc(32px + 12px);padding-left:12px}.ibo-prop--apply.ui-state-error:after{color:#404b5a;content:"";vertical-align:bottom}.ibo-prop--apply.ui-state-error>span{display:none !important}.ibo-prop--cancel{width:calc(32px + 8px);padding-left:8px}.ibo-prop--apply,.ibo-prop--cancel{height:28px}.ibo-prop--apply>span,.ibo-prop--cancel>span{display:block;height:28px;width:32px;text-align:center}.ibo-prop--apply>span>div,.ibo-prop--cancel>span>div{display:inline-flex;justify-content:center;align-items:center;width:100%;height:100%}.ibo-spinner.ibo-is-inline{display:inline-block}.ibo-spinner.ibo-is-inline>*{display:inline-block}.ibo-spinner.ibo-is-small,.ibo-spinner.ibo-is-medium,.ibo-spinner.ibo-is-large{display:flex;flex-direction:column}.ibo-spinner.ibo-is-small>.ibo-spinner--icon,.ibo-spinner.ibo-is-medium>.ibo-spinner--icon,.ibo-spinner.ibo-is-large>.ibo-spinner--icon{align-self:center;color:#929fb1}.ibo-spinner.ibo-is-small>.ibo-spinner--description,.ibo-spinner.ibo-is-medium>.ibo-spinner--description,.ibo-spinner.ibo-is-large>.ibo-spinner--description{align-self:center;color:#404b5a}.ibo-spinner.ibo-is-small>.ibo-spinner--description{margin-top:4px}.ibo-spinner.ibo-is-medium>.ibo-spinner--description{margin-top:8px}.ibo-spinner.ibo-is-large>.ibo-spinner--description{margin-top:16px}.ibo-title{color:#212934;padding:12px 0}.ibo-title--icon{width:90px;height:90px;min-width:90px;min-height:90px;overflow:hidden}.ibo-title--icon>.ibo-title--icon-level-2{width:80px;height:80px;min-width:80px;min-height:80px}.ibo-title--icon>.ibo-title--icon-level-3{width:70px;height:70px;min-width:70px;min-height:70px}.ibo-title--icon-img,.ibo-title--icon-background{width:100%;height:100%;object-position:center;object-fit:contain;background-size:contain}.ibo-title--icon-img--must-contain,.ibo-title--icon-background--must-contain{object-fit:contain;background-size:contain}.ibo-title--icon-img--must-cover,.ibo-title--icon-background--must-cover{object-fit:cover;background-size:cover}.ibo-title--icon-img--must-zoomout,.ibo-title--icon-background--must-zoomout{width:66.67%;height:66.67%}.ibo-title--subtitle{margin-top:2px;margin-bottom:2px;flex-wrap:wrap}.ibo-title-for-dashlet{padding-top:2em}.ibo-title-for-dashlet--content{background-color:white;border-radius:5px;border:1px solid;border-color:#ccd4db;padding-bottom:1em}.ibo-title-separator{border-radius:5px 5px 0 0;border-color:#3182ce;color:#3182ce;background-color:#3182ce;border:3px solid;margin:0;padding:0}:root{--ibo-datatable-panel--table-spacing: 48px}.ibo-datatable--toolbar{display:flex;justify-content:space-between;align-items:center;padding:0 6px;color:#404b5a}.ibo-datatable--toolbar:first-child{margin-bottom:18px}.ibo-datatable--toolbar:not(:first-child){margin-top:18px}.ibo-datatable--toolbar-left>*:not(:first-child),.ibo-datatable--toolbar-right>*:not(:first-child){margin-left:1rem}.ibo-datatable-header{color:#212934}.ibo-datatable-panel>.ibo-panel--body{padding:32px 0 24px}.ibo-datatable--selection-validation-buttons-toolbar{clear:both;margin-top:10px}.ibo-list-column{max-height:150px;overflow-y:auto}.ibo-sort-order::after{color:#dd6c20}.ibo-sort-order.ibo-is-descending::after{content:""}.ibo-sort-order.ibo-is-ascending::after{content:""}.ibo-sort-order.ibo-is-none::after{content:""}.itop-fieldsorter>.selected{background-color:#bee3f8}.ibo-datatable tbody>tr{transition:background-color 300ms linear}.ibo-datatable tbody>tr:hover,.ibo-datatable tbody>tr.selected:hover{cursor:pointer;background-color:#feebc8}.ibo-datatable tbody>tr.selected{background-color:#fbd38d}.ibo-datatable tbody>tr .ibo-datatable--row-actions-toolbar{justify-content:end}.ibo-datatable tbody>tr>[data-attribute-type="AttributeHTML"],.ibo-datatable tbody>tr>[data-attribute-type="AttributeText"],.ibo-datatable tbody>tr>[data-attribute-type="AttributeLongText"]{max-width:100%;overflow:auto}.ibo-datatable--selected-count,.ibo-datatable--result-count{padding-right:0.2em;padding-left:0.1em}.ibo-datatable[data-status="loading"]{margin-top:18px}.ibo-datatable[data-status="loading"] td,.ibo-datatable[data-status="loading"] th{position:relative;padding:10px 12px}.ibo-datatable[data-status="loading"] tr:nth-child(even){background-color:#f2f2f2}.ibo-datatable[data-status="loading"] th{border-bottom:1px solid #ccd4db}.ibo-datatableconfig--attributes-panel .ibo-multi-column .ibo-column:first-child{margin:8px 0;max-height:150px;overflow-y:scroll}.ibo-datatableconfig--attributes-panel--per-page--input{margin:0 4px;max-width:4em;display:initial}.ibo-datatableconfig--settings-panel .ibo-panel--body{display:flex;flex-direction:row}.ibo-datatableconfig--settings-panel--options-container{flex-grow:1}.ibo-datatableconfig--settings-panel--option{display:flex;flex-direction:row;align-items:first baseline;margin-right:4px}.ibo-prop-header{padding-bottom:14px}.help-text{padding:1px 5px;background-color:#d7e3f8;border:1px solid #c6e7f5;border-radius:5px;margin:5px 0;font-size:0.9em}.form-error ul{padding:1px 5px;background-color:#f8d7da;border:1px solid #f5c6cb;border-radius:5px;margin:5px 0;font-size:0.9em}.subform{background-color:#efefef;border-radius:5px;padding:10px}.form-buttons{margin:20px 0}.form select{padding:0;overflow-y:auto}.form select option{height:30px;display:flex;align-items:center}.turbo-refreshing{opacity:0.5}.ibo-field legend{margin-top:24px}collection-entry-element{margin-top:8px;display:block;padding:10px 10px;background-color:#f5f5f5;border-radius:5px}.ts-control{height:auto;min-height:30px}.ibo-form-actions>.ibo-button>span,.ui-dialog .ibo-form-actions>.ui-button>span,.ibo-form-actions>.ui-datepicker-current>span,.ibo-form-actions>.ui-datepicker-close>span{margin-right:5px}.ibo-form textarea{resize:vertical}.ibo-fieldset~.ibo-fieldset:not(.ibo-column),fieldset~.ibo-fieldset:not(.ibo-column),.ibo-fieldset~fieldset:not(.ibo-column){margin-top:48px}.ibo-multi-column~.ibo-fieldset,.ibo-multi-column~fieldset{margin-top:48px}.ibo-fieldset-legend,.ibo-dashboard-editor--properties-subtitle,.ibo-dashboard--available-dashlet--title,.ibo-dashlet--properties--title,legend{width:100%;margin-bottom:16px;padding-bottom:4px;border-bottom:2px solid #aebecd}.ibo-field{}.ibo-field:not([data-attribute-type="AttributeBlob"], [data-attribute-type="AttributeFile"], [data-attribute-type="AttributeImage"], [data-attribute-type="AttributeCustomFields"], [data-attribute-type="AttributeTagSet"], [data-attribute-type="AttributeEnumSet"], [data-attribute-type="AttributeLinkedSet"], [data-attribute-type="AttributeLinkedSetIndirect"], [data-attribute-type="AttributeClassAttCodeSet"], [data-attribute-type="AttributeQueryAttCodeSet"], .ibo-input-file-select--container){}.ibo-field:not([data-attribute-type="AttributeBlob"], [data-attribute-type="AttributeFile"], [data-attribute-type="AttributeImage"], [data-attribute-type="AttributeCustomFields"], [data-attribute-type="AttributeTagSet"], [data-attribute-type="AttributeEnumSet"], [data-attribute-type="AttributeLinkedSet"], [data-attribute-type="AttributeLinkedSetIndirect"], [data-attribute-type="AttributeClassAttCodeSet"], [data-attribute-type="AttributeQueryAttCodeSet"], .ibo-input-file-select--container) .ibo-field--value{word-break:break-word;white-space:inherit}.ibo-field:not([data-attribute-type="AttributeBlob"], [data-attribute-type="AttributeFile"], [data-attribute-type="AttributeImage"], [data-attribute-type="AttributeCustomFields"], [data-attribute-type="AttributeTagSet"], [data-attribute-type="AttributeEnumSet"], [data-attribute-type="AttributeLinkedSet"], [data-attribute-type="AttributeLinkedSetIndirect"], [data-attribute-type="AttributeClassAttCodeSet"], [data-attribute-type="AttributeQueryAttCodeSet"], .ibo-input-file-select--container) .ibo-field--value *:not(input, select, textarea){word-break:break-word;white-space:inherit}.ibo-field:not([data-attribute-type="AttributeBlob"], [data-attribute-type="AttributeFile"], [data-attribute-type="AttributeImage"], [data-attribute-type="AttributeCustomFields"], [data-attribute-type="AttributeTagSet"], [data-attribute-type="AttributeEnumSet"], [data-attribute-type="AttributeLinkedSet"], [data-attribute-type="AttributeLinkedSetIndirect"], [data-attribute-type="AttributeClassAttCodeSet"], [data-attribute-type="AttributeQueryAttCodeSet"], .ibo-input-file-select--container) .ibo-field--value pre{white-space:break-spaces}.ibo-field[data-attribute-type="AttributeImage"]>.ibo-field--value{display:grid}.ibo-field[data-attribute-type="AttributeImage"]>.ibo-field--value>span{display:inherit}.ibo-field[data-attribute-type="AttributeHTML"][data-attribute-flag-read-only="true"],.ibo-field[data-attribute-type="AttributeText"][data-attribute-flag-read-only="true"],.ibo-field[data-attribute-type="AttributeLongText"][data-attribute-flag-read-only="true"]{display:grid}.ibo-field[data-attribute-type="AttributeHTML"][data-attribute-flag-read-only="true"]>.ibo-field--value,.ibo-field[data-attribute-type="AttributeText"][data-attribute-flag-read-only="true"]>.ibo-field--value,.ibo-field[data-attribute-type="AttributeLongText"][data-attribute-flag-read-only="true"]>.ibo-field--value{max-width:100%;overflow:auto}.ibo-field-large{display:block}.ibo-field-large .ibo-field--label{position:relative;display:flex;align-items:center;max-width:initial;width:100%}.ibo-field-large .ibo-field-small .ibo-field--label{display:table-cell;vertical-align:top;padding-right:10px;min-width:100px;max-width:145px;width:30%}.ibo-field-large .ibo-field--value{margin-top:2px}.ibo-field-large .ibo-field--value>*{--ibo-scrollbar--scrollbar-track-background-color: #f2f2f2}.ibo-field-large.ibo-is-fullscreen{background-color:white}.ibo-field-large.ibo-is-fullscreen .ibo-field--label{position:fixed;width:100%;min-width:initial;max-width:initial;padding:4px 8px;background-color:#f8f9fa;border-bottom:1px solid #ccd4db}.ibo-field-large.ibo-is-fullscreen .ibo-field--value{padding:36px 8px 4px 8px}.ibo-field-large.ibo-is-fullscreen .ibo-field--value>*{height:initial !important;width:initial !important}.ibo-field-small{display:table;width:100%}.ibo-field-small .ibo-field--label{display:table-cell;vertical-align:top;padding-right:10px}.ibo-field--fullscreen-toggler{width:20px;height:20px;border-radius:5px;cursor:pointer}.ibo-field--fullscreen-toggler:hover{background-color:#f2f2f2}.ibo-field--label{min-width:100px;max-width:145px;width:30%;word-break:break-word}.ibo-field--label-small .ibo-field--label{width:20em}.ibo-field--value{width:100%;color:#404b5a}.ibo-field--value .HTML table{table-layout:fixed;width:100%}.ibo-field--label>.ibo-field--comments{flex:auto}.ibo-fieldset-legend>.ibo-field--comments,.ibo-dashboard-editor--properties-subtitle>.ibo-field--comments,.ibo-dashboard--available-dashlet--title>.ibo-field--comments,.ibo-dashlet--properties--title>.ibo-field--comments,legend>.ibo-field--comments{padding-bottom:2px;font-size:1.17rem}.ibo-field--comments{display:table-cell;vertical-align:top;width:5em}.ibo-field--comments>input[type="checkbox"]{margin-left:5px;float:right}.ibo-field--comments>.multi_values,.ibo-field--comments>.mono_value,.ibo-field--comments>.ibo-field--comments--synchro{float:right}.mailto,.tel{white-space:nowrap}.mailto .text_decoration,.tel .text_decoration{margin-right:0.5rem;font-size:0.9em}.object-ref-icon.text_decoration,.object-ref-icon-disabled.text_decoration{margin-right:0.5rem}.ibo-field--enable-bulk,.ibo-field--comments--synchro{display:inline;padding:2px 5px;margin:0 0 0 5px;height:calc(100% - 5px);border-radius:5px;font-weight:bold;white-space:nowrap}.ibo-field--enable-bulk--checkbox{margin-left:8px}.ibo-toolbar{display:flex;align-items:center}.ibo-toolbar.ibo-toolbar--action{position:relative}.ibo-toolbar.ibo-toolbar--button{margin-top:16px}.ibo-toolbar-spacer{flex-grow:1}.ibo-toolbar-vertical-separator{display:inline-flex;border-right:1px solid #aebecd;width:1px;height:16px;margin:0 0.75rem}.search_box{box-sizing:border-box;position:relative;z-index:1100;text-align:center}.search_box *{box-sizing:border-box}.search_form_handler{}.search_form_handler input[type="text"],.search_form_handler select{padding:1px 2px}.search_form_handler:not(.closed) .sf_title .sft_short{display:none}.search_form_handler:not(.closed) .sf_title .sft_toggler{transform:rotateX(180deg);transition:transform 0.5s linear}.search_form_handler.closed{margin-bottom:0.5em;width:150px;overflow:hidden;border-radius:4px}.search_form_handler.closed .sf_criterion_area{height:0;opacity:0;padding:0}.search_form_handler.closed .sf_title{padding:6px 8px;text-align:center;font-size:12px}.search_form_handler.closed .sf_title .sft_long{display:none}.search_form_handler.closed .sf_title .sft_hint,.search_form_handler.closed .sf_title .sfobs_hint{display:none}.search_form_handler:not(.no_auto_submit) .sft_hint{display:none}.search_form_handler:not(.no_auto_submit) .sfc_fg_apply{display:none}.search_form_handler.no_auto_submit .sfc_fg_search{display:none}.search_form_handler.no_auto_submit .sft_hint{display:inline-block}.search_form_handler:not(.hide_obsolete_data) .sfobs_hint{display:none}.search_form_handler.hide_obsolete_data .sfobs_hint{display:inline-block}.search_form_handler.hide_obsolete_data.no_auto_submit .sfobs_hint{margin-left:30px}.search_form_handler .sf_message{display:none;margin:8px 8px 0 8px;border-radius:0px}.search_form_handler .sf_criterion_area{padding:8px 8px 3px 8px}.search_form_handler .sf_criterion_area .sf_criterion_row:not(:first-child){margin-top:20px}.search_form_handler .sf_criterion_area .sf_criterion_row:not(:first-child)::before{content:"";position:absolute;top:-12px;left:0px;width:100%;border-top:1px solid #e1e7ec}.search_form_handler .sf_criterion_area .sf_criterion_row:not(:first-child)::after{content:"or";position:absolute;top:-20px;left:8px;padding-left:5px;padding-right:5px;color:#929fb1;background-color:white}.search_form_handler .sf_criterion_area .sf_criterion_row .sf_criterion_group{display:inline}.search_form_handler .sf_criterion_area .sf_criterion_row .sf_criterion_group .sfc_fg_button,.search_form_handler .sf_criterion_area .sf_criterion_row .sf_criterion_group .sfc_header{border:1px solid #d5dde5;border-radius:3px}.search_form_handler .sf_criterion_area .search_form_criteria,.search_form_handler .sf_criterion_area .sf_more_criterion,.search_form_handler .sf_criterion_area .sf_button{position:relative;display:inline-block;margin-right:10px;margin-top:3px;margin-bottom:3px;vertical-align:top}.search_form_handler .sf_criterion_area .search_form_criteria.opened,.search_form_handler .sf_criterion_area .sf_more_criterion.opened,.search_form_handler .sf_criterion_area .sf_button.opened{margin-bottom:0}.search_form_handler .sf_criterion_area .search_form_criteria.opened .sfc_header,.search_form_handler .sf_criterion_area .search_form_criteria.opened .sfm_header,.search_form_handler .sf_criterion_area .sf_more_criterion.opened .sfc_header,.search_form_handler .sf_criterion_area .sf_more_criterion.opened .sfm_header,.search_form_handler .sf_criterion_area .sf_button.opened .sfc_header,.search_form_handler .sf_criterion_area .sf_button.opened .sfm_header{border-bottom:none !important;padding-bottom:13px}.search_form_handler .sf_criterion_area .search_form_criteria>*,.search_form_handler .sf_criterion_area .sf_more_criterion>*,.search_form_handler .sf_criterion_area .sf_button>*{padding:7px 8px;vertical-align:top;border:solid 1px #d5dde5;border-radius:3px}.search_form_handler .sf_criterion_area .search_form_criteria .sfm_content,.search_form_handler .sf_criterion_area .sf_more_criterion .sfm_content,.search_form_handler .sf_criterion_area .sf_button .sfm_content{position:absolute;z-index:-1;min-width:100%;left:0px;margin-top:-1px}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_fg_buttons,.search_form_handler .sf_criterion_area .search_form_criteria .sfm_buttons,.search_form_handler .sf_criterion_area .sf_more_criterion .sfc_fg_buttons,.search_form_handler .sf_criterion_area .sf_more_criterion .sfm_buttons,.search_form_handler .sf_criterion_area .sf_button .sfc_fg_buttons,.search_form_handler .sf_criterion_area .sf_button .sfm_buttons{white-space:nowrap}.search_form_handler .sf_criterion_area .sf_more_criterion,.search_form_handler .sf_criterion_area .sf_button{min-width:34px;text-align:center}.search_form_handler .sf_criterion_area .search_form_criteria{}.search_form_handler .sf_criterion_area .search_form_criteria.locked{background-color:#d5dde5}.search_form_handler .sf_criterion_area .search_form_criteria.locked .sfc_title{user-select:none;cursor:initial}.search_form_handler .sf_criterion_area .search_form_criteria.draft .sfc_header,.search_form_handler .sf_criterion_area .search_form_criteria.draft .sfc_form_group{border-style:dashed;border-color:#929fb1}.search_form_handler .sf_criterion_area .search_form_criteria.draft .sfc_title{font-style:italic}.search_form_handler .sf_criterion_area .search_form_criteria.opened{z-index:1}.search_form_handler .sf_criterion_area .search_form_criteria.opened .sfc_toggle{transform:rotateX(-180deg)}.search_form_handler .sf_criterion_area .search_form_criteria.opened .sfc_form_group{display:flex;flex-direction:column;margin-top:-1px;z-index:-1}.search_form_handler .sf_criterion_area .search_form_criteria.opened_left .sfc_form_group{left:auto;right:0px}.search_form_handler .sf_criterion_area .search_form_criteria:not(:last-of-type){margin-right:12px}.search_form_handler .sf_criterion_area .search_form_criteria>*{background-color:#f2f2f2;color:#212934}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_toggle,.search_form_handler .sf_criterion_area .search_form_criteria .sfc_close{position:absolute;top:7px;color:#dd6c20}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_locked{position:absolute;top:9px;color:#aebecd}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_toggle{display:inline-block;right:23px;transition:all 0.3s ease-in-out}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_close,.search_form_handler .sf_criterion_area .search_form_criteria .sfc_locked{right:7px}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_title{max-width:240px;padding-right:30px;white-space:nowrap;overflow-x:hidden;text-overflow:ellipsis;cursor:pointer}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_title .sfc_values{font-weight:bold}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group{position:absolute;display:none;max-width:450px;width:max-content;max-height:calc(min(512px, 50vh));overflow-x:auto;overflow-y:hidden}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators{display:flex;flex-direction:column;overflow:auto;min-height:0;font-size:12px}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator.force_hide{display:none !important}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator>label{line-height:20px;white-space:nowrap}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator>label>*{display:inline-block;vertical-align:middle}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_radio{width:12px;margin:0;margin-right:7px}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_name{width:96px}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content input[type="text"]{display:unset;width:160px}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_opc_multichoices{display:flex;flex-direction:column;height:100%}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_opc_multichoices label>input{vertical-align:text-top;margin-left:0;margin-right:8px}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_opc_multichoices .sfc_opc_mc_items_wrapper{overflow-y:auto;margin:0 -8px}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_opc_multichoices .sfc_opc_mc_items_wrapper .sfc_opc_mc_items .sfc_opc_mc_items_list{text-align:left}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_opc_multichoices .sfc_opc_mc_items_wrapper .sfc_opc_mc_items .sfc_opc_mc_items_list.sfc_opc_mc_items_selected{position:relative;padding-top:5px;margin-top:5px}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_opc_multichoices .sfc_opc_mc_items_wrapper .sfc_opc_mc_items .sfc_opc_mc_items_list.sfc_opc_mc_items_selected::before{content:"";position:absolute;border-top:1px solid #d5dde5;width:calc(100% - 12px);margin-left:6px;top:0px}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_opc_multichoices .sfc_opc_mc_items_wrapper .sfc_opc_mc_items .sfc_opc_mc_items_list .sfc_opc_mc_placeholder{padding:15px 8px;font-style:italic;text-align:center}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_opc_multichoices .sfc_opc_mc_items_wrapper .sfc_opc_mc_items .sfc_opc_mc_items_list .sfc_opc_mc_item{padding:4px 8px}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_opc_multichoices .sfc_opc_mc_items_wrapper .sfc_opc_mc_items .sfc_opc_mc_items_list .sfc_opc_mc_item:hover{background-color:#e1e7ec}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_opc_multichoices .sfc_opc_mc_items_wrapper .sfc_opc_mc_items .sfc_opc_mc_items_list .sfc_opc_mc_item label{display:inline-block;width:100%}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_opc_multichoices .sfc_opc_mc_items_wrapper .sfc_opc_mc_items_hint{margin-top:15px;margin-bottom:15px;padding-left:9px;padding-right:9px;color:#6e7a8a;font-size:10px;font-style:italic}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_opc_multichoices .sfc_opc_mc_items_wrapper .sfc_opc_mc_items_hint>span{margin-right:0.5em;font-style:italic}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_search,.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_apply,.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_cancel{margin-top:8px;font-size:1rem}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_search,.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_apply{margin-right:5px}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_more,.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_less{position:absolute;bottom:7px;right:0px;cursor:pointer;color:#2c5382;font-size:10px;font-weight:bold;border:none;background-color:transparent}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_more>span,.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_less>span{margin-left:3px}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operator:not(:first-of-type),.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operator:first-of-type .sfc_op_radio{display:none}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_less{display:none}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_more{display:inline-block}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group.advanced .sfc_fg_operator{margin-bottom:3px}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group.advanced .sfc_fg_operator:last-of-type{margin-bottom:0}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group.advanced .sfc_fg_operator:not(:first-of-type),.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group.advanced .sfc_fg_operator:first-of-type .sfc_op_radio{display:inherit}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group.advanced .sfc_fg_less{display:inline-block}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group.advanced .sfc_fg_more{display:none}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group.advanced .hide_on_advanced{display:none}.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group:not(.advanced) .hide_on_less{display:none}.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_raw>*{border-color:transparent}.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_raw .sfc_title{cursor:initial;padding-right:20px}.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_raw .sfc_form_group{display:none}.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_enum .sfc_form_group .sfc_fg_operator_in{display:flex;flex-direction:column;height:100%;min-height:0}.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_enum .sfc_form_group .sfc_fg_operator_in>label{display:flex;height:100%;min-height:0;width:100%;line-height:initial;white-space:nowrap}.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_enum .sfc_form_group .sfc_fg_operator_in>label .sfc_op_content{width:100%}.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_tag_set .sfc_form_group .sfc_fg_operator_in>label{display:inline-block;width:100%;line-height:initial;white-space:nowrap}.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_tag_set .sfc_form_group .sfc_fg_operator_in>label .sfc_op_content{width:100%}.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_numeric .sfc_fg_operators .sfc_fg_operator.sfc_fg_operator_between .sfc_op_content_from_outer{display:inline}.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_numeric .sfc_fg_operators .sfc_fg_operator.sfc_fg_operator_between .sfc_op_content_until_outer{display:inline;margin-left:5px}.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_numeric .sfc_fg_operators .sfc_fg_operator.sfc_fg_operator_between label.sfc_op_content_from_label,.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_numeric .sfc_fg_operators .sfc_fg_operator.sfc_fg_operator_between label.sfc_op_content_until_label{width:45px;display:inline-block}.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_numeric .sfc_fg_operators .sfc_fg_operator.sfc_fg_operator_between input[type="text"]{width:77px}.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_date_time .sfc_form_group.advanced .sfc_fg_operator_between,.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_date .sfc_form_group.advanced .sfc_fg_operator_between{margin-bottom:5px}.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_date_time .sfc_fg_operator_between_days input,.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_date .sfc_fg_operator_between_days input{width:135px}.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_date_time button.ui-datepicker-trigger,.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_date button.ui-datepicker-trigger{background:none;border:none;height:100%;padding:2px}.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_date_time button.ui-datepicker-trigger img,.search_form_handler .sf_criterion_area .search_form_criteria.search_form_criteria_date button.ui-datepicker-trigger img{vertical-align:middle}.search_form_handler .sf_criterion_area .sf_more_criterion.opened{z-index:2}.search_form_handler .sf_criterion_area .sf_more_criterion.opened .sfm_content{display:inherit}.search_form_handler .sf_criterion_area .sf_more_criterion.opened_left .sfm_content{left:auto;right:0px}.search_form_handler .sf_criterion_area .sf_more_criterion>*{background-color:white;color:#37474f}.search_form_handler .sf_criterion_area .sf_more_criterion .sfm_toggler .sfm_tg_title{margin-right:7px}.search_form_handler .sf_criterion_area .sf_more_criterion .sfm_toggler .sfm_tg_icon{color:#dd6c20}.search_form_handler .sf_criterion_area .sf_more_criterion .sfm_content{display:none;min-width:200px}.search_form_handler .sf_criterion_area .sf_more_criterion .sfm_content .sfm_lists{margin:0 -8px;padding:0 8px;max-height:400px;overflow-x:hidden;overflow-y:auto}.search_form_handler .sf_criterion_area .sf_more_criterion .sfm_content .sfm_lists .sfl_items>li:hover{background-color:#e1e7ec}.search_form_handler .sf_criterion_area .sf_more_criterion .sfm_content .sfm_buttons{display:none}.search_form_handler .sf_criterion_area .sf_more_criterion .sfm_content .sfm_buttons button{margin-top:8px;margin-right:5px;padding:3px 6px;font-size:11px}.search_form_handler .sf_criterion_area .sf_more_criterion .sfm_content .sfm_buttons button:last-of-type{margin-right:0}.search_form_handler .sf_criterion_area .sf_button{cursor:pointer}.search_form_handler .sf_criterion_area .sf_button>*{background-color:white;color:#dd6c20}.search_form_handler .sf_list:not(:first-of-type) .sfl_title{border-top:1px solid #ccd4db;padding-top:8px;margin-top:5px}.search_form_handler .sf_list .sfl_title{font-weight:bold}.search_form_handler .sf_list .sfl_items{margin:5px -8px 0 -8px;padding:0;text-align:left}.search_form_handler .sf_list .sfl_items>li{padding:4px 8px;list-style:none;white-space:nowrap}.search_form_handler .sf_list .sfl_items>li:hover{background-color:#e1e7ec}.search_form_handler .sf_list .sfl_items>li.sfl_i_placeholder{font-style:italic;opacity:0.8}.search_form_handler .sf_list .sfl_items>li>label{display:inline-block;width:100%}.search_form_handler .sf_list .sfl_items>li>label>*{vertical-align:middle}.search_form_handler .sf_list .sfl_items>li>label>input[type="checkbox"]{margin-left:0;margin-right:8px}.search_form_handler .sf_filter{position:relative;margin-top:8px;margin-bottom:8px}.search_form_handler .sf_filter input,.search_form_handler .sf_filter button,.search_form_handler .sf_filter .sff_picto{vertical-align:middle;height:22px}.search_form_handler .sf_filter input,.search_form_handler .sf_filter button{border:1px solid #ABABAB}.search_form_handler .sf_filter input{width:100% !important}.search_form_handler .sf_filter button{width:23px;background-color:white;color:#dd6c20;font-size:10px}.search_form_handler .sf_filter button:first-of-type{margin-left:5px}.search_form_handler .sf_filter button:not(:first-of-type){border-left:transparent}.search_form_handler .sf_filter .sff_input_wrapper{position:relative}.search_form_handler .sf_filter .sff_input_wrapper input[type="text"]{display:unset}.search_form_handler .sf_filter .sff_input_wrapper .sff_picto{position:absolute;right:7px;top:3px;user-select:none;color:#404b5a}.search_form_handler .sf_filter .sff_input_wrapper .sff_reset{display:none}.search_form_handler .sf_filter .sff_input_wrapper input::-ms-clear{display:none}.search_form_handler .sf_filter.sf_with_buttons input{width:calc(100% - 28px) !important;min-width:120px}.sft_hint,.sfobs_hint,.sft_toggler{margin-left:8px;color:#404b5a}.sf_results_placeholder{margin-top:24px;text-align:center}.sf_results_placeholder button{margin-top:8px}.sf_results_placeholder button>span{margin-right:0.5em}.ibo-search-form-panel{z-index:3;margin-bottom:8px}.ibo-search-form-panel .ibo-panel--body{padding:18px 14px 10px;overflow:initial}.ibo-search-form-panel .ibo-panel--body::before{border-radius:5px 5px 0 0}#ibo-main-content .search_form_handler .sf_criterion_area{padding:0}.sfm_tg_title{display:none}.ibo-criterion-group:empty~.sf_more_criterion .sfm_tg_title{display:unset}.sf_results_area{z-index:1;margin-bottom:300px}.ibo-search-form-panel .ibo-panel--body.ibo-is-sticking{position:fixed;border-radius:0;border-bottom-color:transparent}.ibo-datatable-panel.ibo-is-sticking .ibo-panel--header,.ibo-datatable-panel.ibo-is-sticking .ibo-object-summary--header{z-index:0}.ibo-datatable-panel.ibo-is-sticking .ibo-datatable--toolbar{position:fixed;z-index:2;padding-bottom:4px;background-color:white;border-left:1px solid #ccd4db;border-right:1px solid #ccd4db}.ibo-datatable-panel.ibo-is-sticking .dataTables_scrollHead{position:fixed !important;z-index:2;background-color:white;border-left:1px solid #ccd4db !important;border-right:1px solid #ccd4db !important}.ibo-field-badge{display:inline-flex;align-items:baseline;margin:0;padding:4px 10px;border-radius:3px;background-color:var(--ibo-main-color);color:var(--ibo-complementary-color)}.ibo-field-badge--decoration+.ibo-field-badge--label{margin-left:0.5rem}.ibo-input-file-select--container .ibo-input-file-select .ibo-input-file-select--file-input{display:none}.ibo-input-file-select--container .ibo-input-file-select .ibo-input-file-select--file-name{margin-left:10px}.ibo-medallion-icon{display:flex;padding:13px 0}.ibo-medallion-icon--image{height:48px;width:48px;padding:2px;border-radius:100%;background-color:#bee3f8}.ibo-medallion-icon--description{display:inline-block;padding-left:8px}@keyframes decreaseHighlight{0%{height:100%}8%{border-radius:0 0 0 3px}100%{height:0}}.ibo-toast{display:inline-flex;position:fixed;align-items:center;max-width:calc(50% - 20px);padding:12px 8px 12px 16px;border-radius:3px;box-shadow:0 2px 4px rgba(0, 0, 0, 0.12), 0 3px 6px rgba(0, 0, 0, 0.15);transition:all 0.4s cubic-bezier(0.215, 0.61, 0.355, 1);z-index:2147483647}.ibo-toast::before{display:block;position:absolute;top:0;left:0;content:"";width:4px;height:100%;top:initial;bottom:0;border-radius:3px 0 0 3px}.ibo-toast.ibo-is-auto-closeable::before{animation:decreaseHighlight 5s linear forwards}.ibo-toast:hover::before{animation:none}.ibo-badge{display:inline-block;white-space:nowrap;padding:2px 4px;border-radius:4px}.ibo-badge.ibo-is-primary{background-color:floralwhite;color:#7b341e}.ibo-badge.ibo-is-secondary,.ui-dialog .ibo-badge.ui-button,.ibo-badge.ui-datepicker-current,.ibo-badge.ui-datepicker-close{background-color:#f8f9fa;color:#212934}.ibo-badge.ibo-is-neutral,.ui-dialog .ibo-badge.ui-button.ui-dialog-titlebar-close{background-color:#f8f9fa;color:#212934}.ibo-badge.ibo-is-information{background-color:#ebf8ff;color:#2a4265}.ibo-badge.ibo-is-success{background-color:#dcedc8;color:#33691e}.ibo-badge.ibo-is-failure{background-color:#fce8e8;color:#742a2a}.ibo-badge.ibo-is-warning{background-color:floralwhite;color:#7b341e}.ibo-badge.ibo-is-danger{background-color:#fce8e8;color:#742a2a}.ibo-badge.ibo-is-grey{background-color:#f8f9fa;color:#212934}.ibo-badge.ibo-is-blue-grey{background-color:#cfd8dc;color:#263238}.ibo-badge.ibo-is-blue{background-color:#ebf8ff;color:#2a4265}.ibo-badge.ibo-is-cyan{background-color:#c9eef2;color:#006164}.ibo-badge.ibo-is-green{background-color:#dcedc8;color:#33691e}.ibo-badge.ibo-is-orange{background-color:floralwhite;color:#7b341e}.ibo-badge.ibo-is-red{background-color:#fce8e8;color:#742a2a}.ibo-badge.ibo-is-pink{background-color:#fff5f7;color:#702459}:root{}.ibo-navigation-menu{position:relative;height:100vh}.ibo-navigation-menu.ibo-is-expanded .ibo-navigation-menu--square-company-logo{display:none}.ibo-navigation-menu.ibo-is-expanded .ibo-navigation-menu--full-company-logo{display:flex}.ibo-navigation-menu.ibo-is-expanded .ibo-navigation-menu--silo-selection{display:inline-block}.ibo-navigation-menu.ibo-is-expanded .ibo-navigation-menu--silo-visual-hint{display:none}.ibo-navigation-menu.ibo-is-expanded .ibo-navigation-menu--body{width:310px}.ibo-navigation-menu.ibo-is-expanded .ibo-navigation-menu--body .ibo-navigation-menu--toggler-bar:nth-child(1){top:4px;left:7px;width:14px;transform:rotateZ(-45deg)}.ibo-navigation-menu.ibo-is-expanded .ibo-navigation-menu--body .ibo-navigation-menu--toggler-bar:nth-child(2){top:8px;left:7px;width:0;opacity:0}.ibo-navigation-menu.ibo-is-expanded .ibo-navigation-menu--body .ibo-navigation-menu--toggler-bar:nth-child(3){top:12px;left:7px;width:14px;transform:rotateZ(45deg)}.ibo-navigation-menu.ibo-is-expanded .ibo-navigation-menu--body .ibo-navigation-menu--menu-group:not(.ibo-is-active):active{border-radius:16px}.ibo-navigation-menu.ibo-is-expanded .ibo-navigation-menu--body .ibo-navigation-menu--bottom-part{padding:24px 0 12px}.ibo-navigation-menu.ibo-is-expanded .ibo-navigation-menu--body .ibo-navigation-menu--bottom-part .ibo-navigation-menu--notifications .ibo-navigation-menu--notifications-toggler{display:none}.ibo-navigation-menu.ibo-is-expanded .ibo-navigation-menu--body .ibo-navigation-menu--bottom-part .ibo-navigation-menu--user-info{height:100%}.ibo-navigation-menu.ibo-is-expanded .ibo-navigation-menu--body .ibo-navigation-menu--bottom-part .ibo-navigation-menu--user-info .ibo-navigation-menu--user-welcome-message,.ibo-navigation-menu.ibo-is-expanded .ibo-navigation-menu--body .ibo-navigation-menu--bottom-part .ibo-navigation-menu--user-info .ibo-navigation-menu--user-notifications,.ibo-navigation-menu.ibo-is-expanded .ibo-navigation-menu--body .ibo-navigation-menu--bottom-part .ibo-navigation-menu--user-info .ibo-navigation-menu--user-organization{display:block}.ibo-navigation-menu.ibo-is-expanded .ibo-navigation-menu--body .ibo-navigation-menu--bottom-part .ibo-navigation-menu--user-info .ibo-navigation-menu--user-picture{margin-top:-60px;width:72px;height:72px;border:solid 3px #263238}.ibo-navigation-menu.ibo-is-expanded .ibo-navigation-menu--body .ibo-navigation-menu--bottom-part .ibo-navigation-menu--user-info .ibo-navigation-menu--user-picture .ibo-navigation-menu--user-picture--image{max-width:72px;max-height:72px}.ibo-navigation-menu.ibo-is-active .ibo-navigation-menu--drawer{right:calc(-1 * 312px)}.ibo-navigation-menu.ibo-is-filtered .ibo-navigation-menu--menu-filter-clear{display:block}.ibo-navigation-menu.ibo-is-filtered .ibo-navigation-menu--menu-nodes{margin-bottom:48px}.ibo-navigation-menu.ibo-is-filtered .ibo-navigation-menu--menu-nodes .ibo-navigation-menu--menu-nodes-title{margin-bottom:8px}.ibo-navigation-menu--body,.ibo-navigation-menu--drawer{height:100vh}.ibo-navigation-menu--body{z-index:1;display:flex;flex-direction:column;justify-content:space-between;align-items:stretch;height:100vh;width:60px;background-color:#263238;transition:width 0.1s ease-in-out}.ibo-navigation-menu--top-part{z-index:2;min-height:120px;padding:12px 16px;overflow:hidden}.ibo-navigation-menu--middle-part{z-index:1;flex-grow:1;overflow-y:auto;padding:24px 16px 16px;scrollbar-width:thin;scrollbar-color:#d5dde5 rgba(255, 255, 255, 0)}.ibo-navigation-menu--middle-part::-webkit-scrollbar{width:5px}.ibo-navigation-menu--middle-part::-webkit-scrollbar-track{background-color:rgba(255, 255, 255, 0)}.ibo-navigation-menu--middle-part::-webkit-scrollbar-thumb{background-color:#d5dde5}.ibo-navigation-menu--bottom-part{z-index:2;padding-top:20px;padding-bottom:16px;height:126px;background-color:#404b5a;justify-content:space-between;flex-direction:column}.ibo-navigation-menu--toggler,.ibo-navigation-menu--menu-group{margin:calc(-1 * 10px) calc(-1 * 8px);padding:10px 8px;border-radius:5px}.ibo-navigation-menu--square-company-logo{display:flex;width:38px;height:38px;margin:0 -5px 44px}.ibo-navigation-menu--square-company-logo>img{object-fit:contain}.ibo-navigation-menu--full-company-logo{display:none;width:310px;height:70px;margin:0 0 12px -16px}.ibo-navigation-menu--full-company-logo>img{object-fit:contain;margin:0 auto}.ibo-navigation-menu--toggler{position:relative;display:inline-flex;width:44px}.ibo-navigation-menu--toggler:hover,.ibo-navigation-menu--toggler:active{background-color:#455a64}.ibo-navigation-menu--toggler:hover .ibo-navigation-menu--toggler-bar,.ibo-navigation-menu--toggler:active .ibo-navigation-menu--toggler-bar{background-color:white}.ibo-navigation-menu--toggler-icon{position:relative;display:flex;height:20px;width:28px}.ibo-navigation-menu--toggler-bar{position:absolute;display:block;height:3px;width:100%;opacity:1;transition:all 0.2s linear;background-color:#d5dde5}.ibo-navigation-menu--toggler-bar:nth-child(1){top:0}.ibo-navigation-menu--toggler-bar:nth-child(2){top:8px}.ibo-navigation-menu--toggler-bar:nth-child(3){top:16px}.ibo-navigation-menu--silo-selection{position:absolute;display:none;width:70%;margin-left:15px}.ibo-navigation-menu--silo-selection .ibo-input-wrapper .ibo-input,.ibo-navigation-menu--silo-selection .ui_tpicker_hour_slider .ibo-input,.ibo-navigation-menu--silo-selection .ui_tpicker_hour_slider .ui-autocomplete-input,.ibo-navigation-menu--silo-selection .ui_tpicker_hour_slider .ui-multiselect,.ibo-navigation-menu--silo-selection .ui_tpicker_hour_slider .dataTables_length select,.dataTables_length .ibo-navigation-menu--silo-selection .ui_tpicker_hour_slider select,.ibo-navigation-menu--silo-selection .ui_tpicker_hour_slider .ui_tpicker_hour_slider>select,.ibo-navigation-menu--silo-selection .ui_tpicker_hour_slider .ui_tpicker_minute_slider>select,.ibo-navigation-menu--silo-selection .ui_tpicker_hour_slider .ui_tpicker_second_slider>select,.ibo-navigation-menu--silo-selection .ui_tpicker_hour_slider select.ibo-input-select-placeholder,.ibo-navigation-menu--silo-selection .ui_tpicker_hour_slider .ibo-datatableconfig--attributes-panel--per-page--input,.ibo-navigation-menu--silo-selection .ui_tpicker_hour_slider .search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content input[type="text"],.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content .ibo-navigation-menu--silo-selection .ui_tpicker_hour_slider input[type="text"],.ibo-navigation-menu--silo-selection .ui_tpicker_hour_slider .search_form_handler .sf_filter .sff_input_wrapper input[type="text"],.search_form_handler .sf_filter .sff_input_wrapper .ibo-navigation-menu--silo-selection .ui_tpicker_hour_slider input[type="text"],.ibo-navigation-menu--silo-selection .ui_tpicker_minute_slider .ibo-input,.ibo-navigation-menu--silo-selection .ui_tpicker_minute_slider .ui-autocomplete-input,.ibo-navigation-menu--silo-selection .ui_tpicker_minute_slider .ui-multiselect,.ibo-navigation-menu--silo-selection .ui_tpicker_minute_slider .dataTables_length select,.dataTables_length .ibo-navigation-menu--silo-selection .ui_tpicker_minute_slider select,.ibo-navigation-menu--silo-selection .ui_tpicker_minute_slider .ui_tpicker_hour_slider>select,.ibo-navigation-menu--silo-selection .ui_tpicker_minute_slider .ui_tpicker_minute_slider>select,.ibo-navigation-menu--silo-selection .ui_tpicker_minute_slider .ui_tpicker_second_slider>select,.ibo-navigation-menu--silo-selection .ui_tpicker_minute_slider select.ibo-input-select-placeholder,.ibo-navigation-menu--silo-selection .ui_tpicker_minute_slider .ibo-datatableconfig--attributes-panel--per-page--input,.ibo-navigation-menu--silo-selection .ui_tpicker_minute_slider .search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content input[type="text"],.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content .ibo-navigation-menu--silo-selection .ui_tpicker_minute_slider input[type="text"],.ibo-navigation-menu--silo-selection .ui_tpicker_minute_slider .search_form_handler .sf_filter .sff_input_wrapper input[type="text"],.search_form_handler .sf_filter .sff_input_wrapper .ibo-navigation-menu--silo-selection .ui_tpicker_minute_slider input[type="text"],.ibo-navigation-menu--silo-selection .ui_tpicker_second_slider .ibo-input,.ibo-navigation-menu--silo-selection .ui_tpicker_second_slider .ui-autocomplete-input,.ibo-navigation-menu--silo-selection .ui_tpicker_second_slider .ui-multiselect,.ibo-navigation-menu--silo-selection .ui_tpicker_second_slider .dataTables_length select,.dataTables_length .ibo-navigation-menu--silo-selection .ui_tpicker_second_slider select,.ibo-navigation-menu--silo-selection .ui_tpicker_second_slider .ui_tpicker_hour_slider>select,.ibo-navigation-menu--silo-selection .ui_tpicker_second_slider .ui_tpicker_minute_slider>select,.ibo-navigation-menu--silo-selection .ui_tpicker_second_slider .ui_tpicker_second_slider>select,.ibo-navigation-menu--silo-selection .ui_tpicker_second_slider select.ibo-input-select-placeholder,.ibo-navigation-menu--silo-selection .ui_tpicker_second_slider .ibo-datatableconfig--attributes-panel--per-page--input,.ibo-navigation-menu--silo-selection .ui_tpicker_second_slider .search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content input[type="text"],.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content .ibo-navigation-menu--silo-selection .ui_tpicker_second_slider input[type="text"],.ibo-navigation-menu--silo-selection .ui_tpicker_second_slider .search_form_handler .sf_filter .sff_input_wrapper input[type="text"],.search_form_handler .sf_filter .sff_input_wrapper .ibo-navigation-menu--silo-selection .ui_tpicker_second_slider input[type="text"],.ibo-navigation-menu--silo-selection .ibo-input-wrapper .ui-autocomplete-input,.ibo-navigation-menu--silo-selection .ibo-input-wrapper .ui-multiselect,.ibo-navigation-menu--silo-selection .ibo-input-wrapper .dataTables_length select,.dataTables_length .ibo-navigation-menu--silo-selection .ibo-input-wrapper select,.ibo-navigation-menu--silo-selection .ibo-input-wrapper .ui_tpicker_hour_slider>select,.ibo-navigation-menu--silo-selection .ibo-input-wrapper .ui_tpicker_minute_slider>select,.ibo-navigation-menu--silo-selection .ibo-input-wrapper .ui_tpicker_second_slider>select,.ibo-navigation-menu--silo-selection .ibo-input-wrapper select.ibo-input-select-placeholder,.ibo-navigation-menu--silo-selection .ibo-input-wrapper .ibo-datatableconfig--attributes-panel--per-page--input,.ibo-navigation-menu--silo-selection .ibo-input-wrapper .search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content input[type="text"],.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content .ibo-navigation-menu--silo-selection .ibo-input-wrapper input[type="text"],.ibo-navigation-menu--silo-selection .ibo-input-wrapper .search_form_handler .sf_filter .sff_input_wrapper input[type="text"],.search_form_handler .sf_filter .sff_input_wrapper .ibo-navigation-menu--silo-selection .ibo-input-wrapper input[type="text"]{padding-right:38px;overflow:hidden}.ibo-navigation-menu--silo-selection .ibo-input-wrapper .ibo-input-select-autocomplete,.ibo-navigation-menu--silo-selection .ui_tpicker_hour_slider .ibo-input-select-autocomplete,.ibo-navigation-menu--silo-selection .ui_tpicker_minute_slider .ibo-input-select-autocomplete,.ibo-navigation-menu--silo-selection .ui_tpicker_second_slider .ibo-input-select-autocomplete{padding-right:60px}.ibo-navigation-menu--silo-selection .ibo-input-wrapper .ibo-input-select-autocomplete~.ibo-input-select--action-button--search,.ibo-navigation-menu--silo-selection .ui_tpicker_hour_slider .ibo-input-select-autocomplete~.ibo-input-select--action-button--search,.ibo-navigation-menu--silo-selection .ui_tpicker_minute_slider .ibo-input-select-autocomplete~.ibo-input-select--action-button--search,.ibo-navigation-menu--silo-selection .ui_tpicker_second_slider .ibo-input-select-autocomplete~.ibo-input-select--action-button--search{margin-left:-42px}.ibo-navigation-menu--silo-selection .ibo-input-wrapper .ibo-input-select-autocomplete~.ibo-input-select--action-button--clear,.ibo-navigation-menu--silo-selection .ui_tpicker_hour_slider .ibo-input-select-autocomplete~.ibo-input-select--action-button--clear,.ibo-navigation-menu--silo-selection .ui_tpicker_minute_slider .ibo-input-select-autocomplete~.ibo-input-select--action-button--clear,.ibo-navigation-menu--silo-selection .ui_tpicker_second_slider .ibo-input-select-autocomplete~.ibo-input-select--action-button--clear{margin-left:-72px}.ibo-navigation-menu--silo-selection .ibo-input-wrapper .ibo-input-select-autocomplete~.ibo-input-select--action-button--hierarchy,.ibo-navigation-menu--silo-selection .ui_tpicker_hour_slider .ibo-input-select-autocomplete~.ibo-input-select--action-button--hierarchy,.ibo-navigation-menu--silo-selection .ui_tpicker_minute_slider .ibo-input-select-autocomplete~.ibo-input-select--action-button--hierarchy,.ibo-navigation-menu--silo-selection .ui_tpicker_second_slider .ibo-input-select-autocomplete~.ibo-input-select--action-button--hierarchy{margin-left:-60px}.ibo-navigation-menu--silo-visual-hint{position:absolute;top:2px;right:0;width:16px;height:16px;background-color:#e53e3e;border:2px solid #263238;border-radius:100%}.ibo-navigation-menu--menu-group{display:flex;justify-content:left;align-items:center;white-space:nowrap;overflow-x:hidden;color:#d5dde5;transition-property:background-color, color, padding, margin, border-radius;transition-duration:0.1s;transition-timing-function:linear}.ibo-navigation-menu--menu-group>.ibo-navigation-menu--menu-group-icon{display:flex}.ibo-navigation-menu--menu-group .ibo-navigation-menu--menu-group-title{flex-grow:1}.ibo-navigation-menu--menu-group:not(:last-child){margin-bottom:20px}.ibo-navigation-menu--menu-group:not(.ibo-is-active):hover,.ibo-navigation-menu--menu-group:not(.ibo-is-active):active{color:white;background-color:#455a64}.ibo-navigation-menu--menu-group:not(.ibo-is-active):active{border-radius:100%}.ibo-navigation-menu--menu-group.ibo-is-active{margin-right:calc(-2 * 8px);padding-right:calc(2 - 8px);color:#37474f;background-color:#f8f9fa;border-radius:5px 0 0 5px}.ibo-navigation-menu--menu-group.ibo-is-active .ibo-navigation-menu--menu-group-icon{color:#ea7d1e}.ibo-navigation-menu--menu-group-icon{width:28px;min-width:28px;justify-content:center;font-size:1.83rem}.ibo-navigation-menu--menu-group-icon::before{width:28px}.ibo-navigation-menu--menu-group-title{margin-left:16px;justify-content:left}.ibo-navigation-menu--drawer{position:absolute;z-index:-1;top:0;bottom:0;right:0;display:flex;flex-direction:column;justify-content:flex-start;width:312px;padding:32px 20px;background-color:#f8f9fa;border-right:1px solid #d5dde5;transition:right 0.2s ease-in-out}.ibo-navigation-menu--menu-filter{position:relative}.ibo-navigation-menu--menu-filter-input{width:100%;padding:8px 10px;color:#212934;background-color:white;border:1px solid #d5dde5;border-radius:3px;padding-right:76px}.ibo-navigation-menu--menu-filter-input::placeholder{color:#6e7a8a}.ibo-navigation-menu--menu-filter-input:-ms-input-placeholder,.ibo-navigation-menu--menu-filter-input::-ms-input-placeholder{color:#6e7a8a}.ibo-navigation-menu--menu-filter-clear{display:none;position:absolute;top:8px;right:60px;padding:3px 3px}.ibo-navigation-menu--menu-filter-hotkey{position:absolute;top:6.5px;right:10px;border:1px solid #ccd4db;border-radius:3px;color:#6e7a8a;padding:2px 4px}.ibo-navigation-menu--menu-filter-hint{position:relative;margin-top:16px;padding-right:12px;color:#6e7a8a}.ibo-navigation-menu--menu-filter-hint-close{position:absolute;top:1px;right:2px}.ibo-navigation-menu--menu--placeholder{width:100%;margin-top:50px}.ibo-navigation-menu--menu--placeholder-image>svg{display:block;width:90%;height:auto;margin:auto}.ibo-navigation-menu--menu--placeholder-hint{margin-top:8px;text-align:center}.ibo-navigation-menu--menu-groups{overflow-y:auto;overflow-x:hidden;margin:50px calc(-1 * 20px) 0 calc(-1 * 20px);padding-left:20px;padding-right:20px;width:inherit}.ibo-navigation-menu--menu-nodes{display:none}.ibo-navigation-menu--menu-nodes ul li>a,.ibo-navigation-menu--menu-nodes ul li>span{margin:0 -10px;padding:6px 10px;border-radius:0;color:#6e7a8a}.ibo-navigation-menu--menu-nodes ul li>a{color:inherit}.ibo-navigation-menu--menu-nodes ul li>a:hover{background-color:#e1e7ec;border-radius:5px}.ibo-navigation-menu--menu-nodes ul ul{padding-left:20px}.ibo-navigation-menu--menu-nodes.ibo-is-active{display:block}.ibo-navigation-menu--menu-nodes-title{margin-top:0;margin-bottom:32px;word-break:break-word}.ibo-navigation-menu--menu-node-title{display:flex;justify-content:space-between;align-items:center}.ibo-navigation-menu--menu-node-counter{margin-left:8px;padding:2px 6px;width:34px;min-width:34px;text-align:center;background:#e1e7ec;border-radius:5px}.ibo-navigation-menu--notifications{position:relative;display:flex;flex-direction:column;align-content:center}.ibo-navigation-menu--notifications-toggler{position:relative;font-size:2rem;color:#929fb1}.ibo-navigation-menu--notifications-toggler:hover,.ibo-navigation-menu--notifications-toggler.ibo-is-loaded:hover{color:#f2f2f2}.ibo-navigation-menu--notifications-toggler.ibo-is-loaded{color:#d5dde5}.ibo-navigation-menu--notifications-toggler.ibo-is-loaded:not(.ibo-is-empty) .ibo-navigation-menu--notifications-toggler--new-messages{display:inline}.ibo-navigation-menu--notifications-toggler .ibo-navigation-menu--notifications-toggler--new-messages{top:-2px;right:-7px;width:16px;height:16px}.ibo-navigation-menu--user-notifications--toggler{position:relative}.ibo-navigation-menu--user-notifications--toggler.ibo-is-loaded{color:#d5dde5}.ibo-navigation-menu--user-notifications--toggler.ibo-is-loaded:not(.ibo-is-empty) .ibo-navigation-menu--notifications-toggler--new-messages{display:inline}.ibo-navigation-menu--user-notifications--toggler .ibo-navigation-menu--notifications-toggler--new-messages{top:-2px;right:-5px;width:10px;height:10px}.ibo-navigation-menu--notifications-toggler--new-messages{position:absolute;display:none;background-color:#e53e3e;border:2px solid #404b5a;border-radius:100%}.ibo-navigation-menu--user-info{justify-content:space-between;flex-direction:column}.ibo-navigation-menu--user-info .ibo-navigation-menu--user-picture{width:36px;height:36px;overflow:hidden;background-color:#d5dde5;border-radius:100%}.ibo-navigation-menu--user-info .ibo-navigation-menu--user-picture .ibo-navigation-menu--user-picture--image{display:flex;max-width:36px;max-height:36px}.ibo-navigation-menu--user-info .ibo-navigation-menu--user-welcome-message,.ibo-navigation-menu--user-info .ibo-navigation-menu--user-organization,.ibo-navigation-menu--user-info .ibo-navigation-menu--user-notifications{display:none;text-align:center;color:white}.ibo-navigation-menu--user-info .ibo-navigation-menu--user-welcome-message .ibo-navigation-menu--user-welcome-message--text,.ibo-navigation-menu--user-info .ibo-navigation-menu--user-welcome-message .ibo-navigation-menu--user-welcome-message--toggler{color:white}.ibo-navigation-menu--user-info .ibo-navigation-menu--user-welcome-message--toggler{padding-left:6px}.ibo-navigation-menu--user-info .ibo-navigation-menu--user-notifications .ibo-navigation-menu--user-notifications--text{color:white}.ibo-navigation-menu--user-info .ibo-navigation-menu--user-notifications .ibo-navigation-menu--user-notifications--toggler--icon{padding-left:5px}.ibo-navigation-menu--user-info .ibo-navigation-menu--user-organization{color:#ebf8ff}.ibo-navigation-menu--user-info .ibo-navigation-menu--user-menu-container{position:absolute;bottom:10px}.ibo-navigation-menu--user-info .ibo-navigation-menu--user-menu-container .ibo-popover-menu>.ibo-popover-menu--section:nth-child(odd),.ibo-navigation-menu--user-info .ibo-navigation-menu--user-menu-container .ui-menu>.ibo-popover-menu--section:nth-child(odd),.ibo-navigation-menu--user-info .ibo-navigation-menu--user-menu-container .ui-menu>.ui-multiselect-checkboxes:nth-child(odd),.ibo-navigation-menu--user-info .ibo-navigation-menu--user-menu-container .ui-multiselect-menu>.ibo-popover-menu--section:nth-child(odd),.ibo-navigation-menu--user-info .ibo-navigation-menu--user-menu-container .ui-multiselect-menu>.ui-multiselect-checkboxes:nth-child(odd),.ibo-navigation-menu--user-info .ibo-navigation-menu--user-menu-container .ibo-input-select-icon--menu>.ibo-popover-menu--section:nth-child(odd),.ibo-navigation-menu--user-info .ibo-navigation-menu--user-menu-container .ibo-input-select-icon--menu>.ui-multiselect-checkboxes:nth-child(odd),.ibo-navigation-menu--user-info .ibo-navigation-menu--user-menu-container .graph_config .toolkit_menu.graph>ul>li ul>.ibo-popover-menu--section:nth-child(odd),.ibo-navigation-menu--user-info .ibo-navigation-menu--user-menu-container .graph_config .toolkit_menu.graph>ul>li ul>.ui-multiselect-checkboxes:nth-child(odd),.graph_config .toolkit_menu.graph>ul>li .ibo-navigation-menu--user-info .ibo-navigation-menu--user-menu-container ul>.ibo-popover-menu--section:nth-child(odd),.ibo-navigation-menu--user-info .ibo-navigation-menu--user-menu-container .ibo-popover-menu>.ui-multiselect-checkboxes:nth-child(odd){background-color:#f8f9fa}:root{--ibo-top-bar--height: 54px;--ibo-top-bar--padding-left: 16px;--ibo-top-bar--padding-right: 16px;--ibo-top-bar--padding-y: 0;--ibo-top-bar--background-color: white;--ibo-top-bar--elements-spacing: 32px;--ibo-top-bar--quick-actions--margin-right: 32px}.ibo-top-bar{height:var(--ibo-top-bar--height);padding:var(--ibo-top-bar--padding-y) var(--ibo-top-bar--padding-right) var(--ibo-top-bar--padding-y) var(--ibo-top-bar--padding-left);background-color:var(--ibo-top-bar--background-color)}.ibo-top-bar .ibo-breadcrumbs{flex-grow:1;overflow-x:hidden}.ibo-top-bar--quick-actions{margin-right:var(--ibo-top-bar--quick-actions--margin-right)}.ibo-top-bar--toolbar-dashboard-title{max-width:350px}.ibo-top-bar--toolbar-dashboard-menu-toggler{display:flex;align-items:center}#ibo-center-container.ibo-center-container--with-side-content{display:flex;align-items:stretch}#ibo-center-container.ibo-center-container--with-side-content #ibo-main-content{flex-grow:1}.ibo-v-spacer{padding-top:1em}#ibo-side-content{background-color:white;border-left:1px solid #ccd4db}.ibo-details{margin-top:5px}.ibo-tab-container:not(.ibo-is-scrollable):not([data-status="loaded"]) .ibo-tab-container--tab-container:not(:first-child){display:none}.ibo-tab-container--tabs-list{position:relative;height:36px;background-color:#f8f9fa}.ibo-tab-container--tab-header,.ibo-tab-container--extra-tabs-container{color:#404b5a}.ibo-tab-container--tab-header:hover:not(.ui-state-disabled),.ibo-tab-container--extra-tabs-container:hover:not(.ui-state-disabled){color:#2c5382;background-color:#e1e7ec}.ibo-tab-container--tab-header.ui-tabs-active,.ui-tabs-active.ibo-tab-container--extra-tabs-container{color:#2c5382}.ibo-tab-container--tab-toggler,.ibo-tab-container--extra-tabs-list-toggler{padding-left:24px;padding-right:24px}.ibo-tab-container--extra-tabs-container{position:absolute;top:0;bottom:0;right:0;background-color:#f8f9fa}.ibo-tab-container--extra-tabs-list-toggler{padding-left:12px;padding-right:12px}.ibo-tab-container--extra-tabs-list{position:fixed;z-index:10;max-height:300px;display:flex;flex-direction:column;overflow-y:auto;background-color:#f8f9fa;border-radius:3px}.ibo-tab-container--extra-tab-toggler{padding:8px 16px;max-width:220px;color:#6e7a8a;overflow-x:clip}.ibo-tab-container--extra-tab-toggler:hover,.ibo-tab-container--extra-tab-toggler:active{color:#2c5382;background-color:#e1e7ec}.ibo-tab-container--extra-tab-toggler--tooltip-title{margin-bottom:16px}.ibo-tab-container--tab-container{padding:32px 32px;overflow-x:auto}.ibo-tab-container--tab-container-list.ibo-is-scrollable .ibo-tab-container--tab-container:not(:first-child:nth-last-child(2)) .ibo-tab-container--tab-container--label{display:block}.ibo-tab-container--tab-container-list.ibo-is-scrollable .ibo-tab-container--tab-container{min-height:auto}.ibo-tab-container--tab-container-list.ibo-is-scrollable .ibo-tab-container--tab-container:last-child:not(:only-child){min-height:60vh}.ibo-tab-container--tab-container--label{display:none;margin-bottom:20px;overflow-x:hidden}.ibo-tab-container--tab-container--label>span{position:relative;padding-left:20px;margin-left:40px;color:#929fb1}.ibo-tab-container--tab-container--label>span::before,.ibo-tab-container--tab-container--label>span::after{content:"";display:inline-block;position:absolute;top:calc(50% - (2px / 2));height:1px;width:10000px;border-top:2px solid #929fb1}.ibo-tab-container--tab-container--label>span::before{right:100%}.ibo-tab-container--tab-container--label>span::after{left:100%;margin-left:20px}.ibo-tab--temporary-remote-content{position:relative}.ibo-tab--temporary-remote-content--placeholder{position:relative;height:auto;max-height:300px;text-align:center}.ibo-tab--temporary-remote-content--placeholder>svg{max-width:calc(300px * 5.4);max-height:300px}.ibo-tab--temporary-remote-content--button{position:absolute;top:0;display:flex;justify-content:center;align-content:center;flex-direction:column;text-align:center;height:100%;width:100%;cursor:pointer;background-color:transparent;color:#404b5a}.ibo-tab--temporary-remote-content--button:hover{opacity:0.5;background-color:#212934;color:#e1e7ec}.ibo-multi-column{display:flex;flex-wrap:wrap;margin:0 -16px;row-gap:48px}.ibo-column{min-width:300px;flex-grow:1;flex-shrink:1;padding:0 16px;flex-basis:10%}.ibo-column:not(:last-child) .ibo-column:not(.ibo-without-margin){margin-bottom:48px}.ibo-mini-column{min-width:30px;flex-grow:1;flex-shrink:1;padding:0 16px;flex-basis:10%;display:flex;flex-direction:column}.ibo-mini-column>.ibo-button,.ui-dialog .ibo-mini-column>.ui-button,.ibo-mini-column>.ui-datepicker-current,.ibo-mini-column>.ui-datepicker-close{margin-left:0;margin-right:0}.ibo-mini-column:not(:last-child){margin-bottom:48px}.ibo-dashboard--top-bar{display:flex;justify-content:space-between;align-items:center;padding-bottom:20px}.ibo-dashboard--top-bar .ibo-dashboard--top-bar-toolbar{display:flex;align-items:center}.ibo-dashboard--selector{display:flex;align-items:center;margin-left:12px;margin-right:1}.ibo-dashboard--selector:hover{background-color:#f8f9fa;border-radius:4px}.ibo-dashboard--selector .selector-label{display:inline-block;margin-left:10px;margin-right:10px;vertical-align:super}.ibo-dashboard--grid{width:100%}.ibo-dashboard--grid-row{display:flex;flex-direction:row;justify-content:space-between;overflow:hidden}.ibo-dashboard--grid-row:not(:last-child){padding-bottom:calc(24px / 2)}.ibo-dashboard--grid-row:not(:first-child){padding-top:calc(24px / 2)}.ibo-dashboard--grid-column{display:flex;flex-flow:row wrap;align-items:flex-start;align-content:flex-start;width:calc(100% + (2 * 24px));margin:calc(-1 * 24px / 2) calc(-1 * 24px / 2);min-width:0}.ibo-dashboard--grid-column:not(:last-child){margin-right:0}.ibo-dashboard--grid-column:not(:first-child){margin-left:0}.ibo-dashboard--grid-column.edit_mode{margin:1px;border:2px #ccd4db dashed;width:100%;min-height:40px}.ibo-dashboard--switch{position:relative;display:inline-block;width:30px;height:24px;vertical-align:baseline}.ibo-dashboard--switch input{display:none}.ibo-dashboard--slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0}.ibo-dashboard--slider:before{content:"";font-size:0.83rem;color:#404b5a;position:absolute;right:5px;bottom:3px}.ibo-dashboard--slider:after{content:"";font-size:1.17rem;color:#dd6c20;position:absolute;left:6px;bottom:1px}input:checked+.ibo-dashboard--slider:before{content:""}input:checked+.ibo-dashboard--slider:after{content:""}.ibo-dashboard-editor--pane{flex-grow:1;padding:16px 30px 16px 15px;overflow:auto}.ibo-dashboard-editor--available-dashlet-icon{display:inline-block;height:34px;width:34px;margin:2px 5px;cursor:grab}.ibo-dashboard-editor--available-dashlet-icon:active{cursor:move}.ibo-dashboard-editor--properties,.ibo-dashboard--available-dashlets,.ibo-dashlet--properties{display:flex;flex-direction:column;padding-bottom:20px}.ibo-dashboard-editor--properties table,.ibo-dashboard--available-dashlets table,.ibo-dashlet--properties table{width:100%;text-align:left}.ibo-dashboard-editor--properties table td,.ibo-dashboard-editor--properties table th,.ibo-dashboard--available-dashlets table td,.ibo-dashboard--available-dashlets table th,.ibo-dashlet--properties table td,.ibo-dashlet--properties table th{margin-bottom:14px}.ibo-dashboard-editor--properties-title{padding-bottom:2rem}.ibo-dashboard-editor--layout-list{display:flex;justify-content:center;padding-bottom:12px}.ibo-dashboard-editor--layout-list>.ui-button{display:inline-block;height:auto;margin:0 15px 0 5px}.ibo-dashboard--available-dashlets--list{display:flex;justify-content:center;flex-wrap:wrap}#dashboard_editor{display:flex;flex-direction:row;padding:0}#dashboard_editor>.itop-dashboard{resize:horizontal;overflow:scroll;border-right:solid 1px #e1e7ec;padding:16px 15px 16px 30px}.ibo-dashboard-editor--delete-dashlet-icon{position:absolute;top:7px;right:9px;padding:2px 6px;z-index:21}.ibo-dashboard-editor .itop-dashboard a{cursor:not-allowed}.ibo-wizard-container{padding:10px 16px;background:#bee3f8;border-radius:3px;border-left:3px solid #3182ce}.ibo-object-details.ibo-has-icon.ibo-has-medallion-icon>.ibo-panel--header .ibo-panel--header-left,.ibo-object-details.ibo-has-icon.ibo-has-medallion-icon>.ibo-object-summary--header .ibo-panel--header-left{margin-left:32px;padding-left:96px}.ibo-object-details.ibo-has-icon.ibo-has-medallion-icon>.ibo-panel--header .ibo-panel--header-left .ibo-panel--icon,.ibo-object-details.ibo-has-icon.ibo-has-medallion-icon>.ibo-object-summary--header .ibo-panel--header-left .ibo-panel--icon{bottom:calc(-1 * 96px / 2 + -12px);width:96px;height:96px;min-width:96px;min-height:96px}.ibo-object-details.ibo-has-icon.ibo-has-medallion-icon>.ibo-panel--header .ibo-panel--header-left .ibo-panel--titles,.ibo-object-details.ibo-has-icon.ibo-has-medallion-icon>.ibo-object-summary--header .ibo-panel--header-left .ibo-panel--titles{padding-left:32px}.ibo-object-details--status-dot{width:10px;height:10px;min-width:10px;min-height:10px;border-radius:100%}.ibo-object-details--status-dot+.ibo-object-details--status-label{margin-left:8px}.ibo-object-details--status+.ibo-object-details--object-class{margin-left:0.5rem;display:inline-flex}.ibo-object-details--status+.ibo-object-details--object-class::before{content:"("}.ibo-object-details--status+.ibo-object-details--object-class::after{content:")"}.ibo-object-details--tag{color:#404b5a}.ibo-object-details--tag:not(:first-child){margin-left:12px}.ibo-object-details--tag-icon{margin-right:6px;color:#6e7a8a}.ibo-object-details--object-class~.ibo-object-details--tag::before,.ibo-object-details--tag~.ibo-object-details--tag::before{content:" ";display:inline-block;vertical-align:middle;margin-right:12px;width:5px;height:5px;border-radius:100%;background-color:#404b5a}.ibo-object-details.ibo-has-sticky-header>.ibo-panel--header,.ibo-object-details.ibo-has-sticky-header>.ibo-object-summary--header{}.ibo-object-details.ibo-has-sticky-header>.ibo-panel--header.ibo-is-sticking .ibo-object-details--object-class,.ibo-object-details.ibo-has-sticky-header>.ibo-is-sticking.ibo-object-summary--header .ibo-object-details--object-class{display:none}.ibo-object-details.ibo-has-sticky-header.ibo-has-icon.ibo-has-medallion-icon>.ibo-panel--header,.ibo-object-details.ibo-has-sticky-header.ibo-has-icon.ibo-has-medallion-icon>.ibo-object-summary--header{}.ibo-object-details.ibo-has-sticky-header.ibo-has-icon.ibo-has-medallion-icon>.ibo-panel--header.ibo-is-sticking .ibo-panel--header-left,.ibo-object-details.ibo-has-sticky-header.ibo-has-icon.ibo-has-medallion-icon>.ibo-is-sticking.ibo-object-summary--header .ibo-panel--header-left{padding-left:48px}.ibo-object-details.ibo-has-sticky-header.ibo-has-icon.ibo-has-medallion-icon>.ibo-panel--header.ibo-is-sticking .ibo-panel--header-right,.ibo-object-details.ibo-has-sticky-header.ibo-has-icon.ibo-has-medallion-icon>.ibo-is-sticking.ibo-object-summary--header .ibo-panel--header-right{padding-right:8px}.ibo-object-details.ibo-has-sticky-header.ibo-has-icon.ibo-has-medallion-icon>.ibo-panel--header.ibo-is-sticking .ibo-panel--titles,.ibo-object-details.ibo-has-sticky-header.ibo-has-icon.ibo-has-medallion-icon>.ibo-is-sticking.ibo-object-summary--header .ibo-panel--titles{padding-left:32px}.ibo-object-summary.ibo-has-medallion-icon .ibo-panel--titles{padding-left:16px}.ibo-object-summary>.ibo-panel--body{display:flex;flex-direction:column;padding:0;max-height:40vh;box-shadow:0 3px 6px rgba(0, 0, 0, 0.1), 0 10px 20px rgba(0, 0, 0, 0.15)}.ibo-object-summary--header{margin:8px 0 0 0;padding:8px 0;background-color:#f8f9fa;border-bottom:solid 1px #ccd4db}.ibo-object-summary--header .ibo-panel--icon{overflow:hidden;background-color:#f8f9fa;border:1px solid #90a4ae;border-radius:100%}.ibo-object-summary--header .ibo-panel--header-left{margin-left:16px}.ibo-object-summary--header .ibo-panel--header-right{align-self:start;margin-right:16px;margin-left:8px}.ibo-object-summary--body{overflow:auto}.ibo-object-summary--content--attributes{display:table;width:calc(100% - (2 * 16px));margin:16px 16px 24px 16px}.ibo-object-summary--content--attributes--code,.ibo-object-summary--content--attributes--value{display:table-cell}.ibo-activity-panel{position:relative;display:flex;flex-direction:column;width:480px;height:100%;transition:width 0.2s ease-in-out}.ibo-activity-panel.ibo-is-expanded{width:60vw}.ibo-activity-panel.ibo-is-expanded .ibo-activity-panel--expand-icon{display:none}.ibo-activity-panel:not(.ibo-is-expanded) .ibo-activity-panel--reduce-icon{display:none}.ibo-activity-panel.ibo-is-closed{width:32px}.ibo-activity-panel.ibo-is-closed .ibo-activity-panel--header,.ibo-activity-panel.ibo-is-closed .ibo-activity-panel--body,.ibo-activity-panel.ibo-is-closed .ibo-activity-panel--add-caselog-entry-button{display:none}.ibo-activity-panel.ibo-is-closed .ibo-activity-panel--closed-cover{display:inherit}.ibo-activity-panel--header{position:relative;background-color:#f8f9fa}.ibo-activity-panel--header .ibo-activity-panel--togglers a{color:#404b5a}.ibo-activity-panel--togglers{display:flex;align-items:center}.ibo-activity-panel--actions{display:flex;align-items:center;flex-grow:0;position:sticky;padding-right:16px;background-color:#f8f9fa;color:#929fb1}.ibo-activity-panel--actions:hover{color:#404b5a}.ibo-activity-panel--actions>*:not(:first-child){margin-left:0.75rem}.ibo-activity-panel--tabs-togglers{display:flex;align-items:center;justify-content:safe center;flex-grow:1;padding-left:48px;overflow-x:auto}.ibo-activity-panel--tab-toggler.ibo-is-active .ibo-activity-panel--tab-title{background-color:#e1e7ec}.ibo-activity-panel--tab-toggler.ibo-is-active .ibo-activity-panel--tab-title-messages-count{display:none}.ibo-activity-panel--tab-toggler.ibo-is-draft .ibo-activity-panel--tab-title-draft-indicator{display:initial}.ibo-activity-panel--tab-toggler-for-caselog-1 .ibo-activity-panel--tab-title-decoration{background-color:#689f38}.ibo-activity-panel--tab-toggler-for-caselog-2 .ibo-activity-panel--tab-title-decoration{background-color:#b83280}.ibo-activity-panel--tab-toggler-for-caselog-3 .ibo-activity-panel--tab-title-decoration{background-color:#f6ae55}.ibo-activity-panel--tab-toggler-for-caselog-4 .ibo-activity-panel--tab-title-decoration{background-color:#3182ce}.ibo-activity-panel--tab-toggler-for-caselog-5 .ibo-activity-panel--tab-title-decoration{background-color:#80deea}.ibo-activity-panel--tab-toggler-for-caselog-6 .ibo-activity-panel--tab-title-decoration{background-color:#c5e1a5}.ibo-activity-panel--tab-toggler-for-caselog-7 .ibo-activity-panel--tab-title-decoration{background-color:#fbb6ce}.ibo-activity-panel--tab-title{padding:8px 16px}.ibo-activity-panel--tab-title:hover{background-color:#e1e7ec}.ibo-activity-panel--tab-title-decoration{display:inline-flex;margin-right:8px;width:12px;height:12px;border-radius:3px}.ibo-activity-panel--tab-title-messages-count{display:inline-block;margin-left:8px;background-color:#e1e7ec;padding:0 4px;border-radius:3px}.ibo-activity-panel--tab-title-messages-count[data-messages-count="0"]{display:none}.ibo-activity-panel--tab-title-draft-indicator{display:none;margin-left:8px}.ibo-activity-panel--tab-title-text{max-width:100px}.ibo-activity-panel--tab-toolbar{display:none;flex-direction:column;padding-left:10px;padding-right:10px;background-color:#e1e7ec}.ibo-activity-panel--tab-toolbar.ibo-is-active{display:flex}.ibo-activity-panel--tab-toolbar-actions{justify-content:space-between;flex-wrap:nowrap;margin:4px 0;height:32px}.ibo-activity-panel--tab-toolbar-left-actions .ibo-activity-panel--tab-toolbar-action:not(:first-child)::before{content:"-";margin:0 8px}.ibo-activity-panel--tab-toolbar-middle-actions .ibo-activity-panel--tab-toolbar-action>input{margin-right:8px}.ibo-activity-panel--tab-toolbar-middle-actions .ibo-activity-panel--tab-toolbar-action:not(:first-child){margin-left:18px}.ibo-activity-panel--tab-toolbar-right-actions .ibo-activity-panel--tab-toolbar-info{color:#212934}.ibo-activity-panel--tab-toolbar-right-actions .ibo-activity-panel--tab-toolbar-info>.ibo-activity-panel--tab-toolbar-info-icon{margin-left:8px}.ibo-activity-panel--tab-toolbar-right-actions .ibo-activity-panel--tab-toolbar-info:not(:first-child){margin-left:16px}.ibo-activity-panel--tab-toolbar-action{position:relative;color:#212934}.ibo-activity-panel--filter{cursor:pointer}.ibo-activity-panel--filter-options-toggler{padding-left:0.5rem;color:#212934}.ibo-activity-panel--filter-options-toggler.ibo-is-closed{transform:rotateX(180deg)}.ibo-activity-panel--filter-options-toggler.ibo-is-closed+.ibo-activity-panel--filter-options{display:none}.ibo-activity-panel--filter-options{position:absolute;z-index:1;display:flex;flex-direction:column;top:24px;left:-12px;max-width:200px;padding:8px 12px;background-color:#e1e7ec;border-radius:3px}.ibo-activity-panel--filter-option{cursor:pointer}.ibo-activity-panel--filter-option:not(:first-child){margin-top:8px}.ibo-activity-panel--filter-option-input{margin-right:0.5rem}.ibo-activity-panel--body{flex-grow:1;overflow:auto;padding:16px 16px}.ibo-activity-panel--body--placeholder{margin-top:16px}.ibo-activity-panel--body--placeholder-image>svg{width:250px;height:inherit}.ibo-activity-panel--body--placeholder-hint{margin-top:16px;color:#404b5a}.ibo-activity-panel--add-caselog-entry-button{position:absolute;z-index:1;right:12px;top:88px;width:36px;height:36px;background-color:#dd6c20;color:white;border-radius:100%;box-shadow:0 1px 2px rgba(0, 0, 0, 0.25), 0 1px 3px rgba(0, 0, 0, 0.12)}.ibo-activity-panel--add-caselog-entry-button>i{text-align:center;height:100%;width:100%;font-size:1.33rem;line-height:33px}.ibo-activity-panel--add-caselog-entry-button:hover{color:white;background-color:#ea7d1e;box-shadow:0 2px 4px rgba(0, 0, 0, 0.12), 0 3px 6px rgba(0, 0, 0, 0.15)}.ibo-activity-panel--add-caselog-entry-button:active{color:white;background-color:#c05621}.ibo-activity-panel--add-caselog-entry-button.ibo-is-hidden{display:none}.ibo-activity-panel .ibo-activity-panel--entry-forms-confirmation-dialog{display:none}.ibo-activity-panel--entry-forms-confirmation-explanation{margin-bottom:16px}.ibo-activity-panel--entry-forms-confirmation-preference-input{margin-right:0.5rem}.ibo-activity-panel--closed-cover{display:none;position:absolute;z-index:2;top:0;bottom:0;left:0;right:0;background-color:#f8f9fa;cursor:pointer}.ibo-activity-panel--closed-content-container{transform:rotateZ(-90deg);white-space:nowrap}.ibo-activity-panel--open-icon{margin-left:0.75rem}.ibo-caselog-entry-form{display:block;width:100%;background-color:#e1e7ec}.ibo-caselog-entry-form.ibo-is-closed{display:none}.ibo-caselog-entry-form--actions{display:flex;justify-content:space-between;margin-top:8px;margin-bottom:8px}.ibo-caselog-entry-form--lock-indicator{margin-top:12px}.ibo-caselog-entry-form--lock-icon{width:32px;min-width:32px;height:32px;min-height:32px;color:#fcfcfd;background-color:#404b5a;border-radius:100%}.ibo-caselog-entry-form--lock-message{margin-left:1rem}.ibo-caselog-entry-form--action-buttons--main-actions{}.ibo-caselog-entry-form--action-buttons--main-actions>.ibo-popover-menu,.ibo-caselog-entry-form--action-buttons--main-actions>.ui-menu,.ibo-caselog-entry-form--action-buttons--main-actions>.ui-multiselect-menu,.ibo-caselog-entry-form--action-buttons--main-actions>.ibo-input-select-icon--menu,.graph_config .toolkit_menu.graph>ul>li .ibo-caselog-entry-form--action-buttons--main-actions>ul{z-index:1}.ibo-activity-panel--entry-group:not(:last-child){margin-bottom:24px}.ibo-activity-entry{display:flex;flex-direction:row;align-items:flex-end}.ibo-activity-entry:not(:last-child) .ibo-activity-entry--medallion{visibility:hidden}.ibo-activity-entry:not(:last-child) .ibo-activity-entry--sub-information{margin-bottom:4px}.ibo-activity-entry.ibo-is-current-user{flex-direction:row-reverse;min-width:min-content}.ibo-activity-entry.ibo-is-current-user .ibo-activity-entry--medallion{margin-right:initial;margin-left:8px}.ibo-activity-entry.ibo-is-current-user .ibo-activity-entry--information{margin-right:0;margin-left:40px}.ibo-activity-entry.ibo-is-current-user .ibo-activity-entry--main-information{background-color:#ebf8ff}.ibo-activity-entry.ibo-is-current-user .ibo-activity-entry--sub-information{text-align:right}.ibo-activity-entry.ibo-is-current-user:last-child .ibo-activity-entry--main-information{border-bottom-right-radius:0;border-bottom-left-radius:5px}.ibo-activity-entry:not(.ibo-is-current-user){}.ibo-activity-entry:not(.ibo-is-current-user) .ibo-activity-entry--information{margin-right:40px;margin-left:0}.ibo-activity-entry:not(.ibo-is-current-user):last-child .ibo-activity-entry--main-information{border-bottom-right-radius:5px;border-bottom-left-radius:0}.ibo-activity-entry.ibo-is-closed .ibo-activity-entry--main-information{max-height:48px;overflow:hidden;cursor:pointer}.ibo-activity-entry.ibo-is-closed .ibo-activity-entry--main-information::after{content:"...";position:absolute;top:30px;left:0;padding-left:16px;width:100%;height:100%;background-color:inherit}.ibo-activity-entry--medallion{margin-right:8px;margin-bottom:18px;min-width:32px;width:32px;min-height:32px;height:32px;overflow:hidden;border-radius:100%}.ibo-activity-entry--medallion.ibo-has-image{background-color:#ebf8ff;box-shadow:inset 0 1px 2px 0 rgba(0, 0, 0, 0.25)}.ibo-activity-entry--medallion:not(.ibo-has-image){background-color:#546e7a;color:white;border:1px solid #e1e7ec}.ibo-activity-entry--medallion .ibo-activity-entry--author-picture{max-height:100%}.ibo-activity-entry--main-information{position:relative;display:flex;flex-direction:row;align-items:baseline;padding:12px 16px;color:#404b5a;background-color:#e1e7ec;border-radius:5px}.ibo-activity-entry--main-information-icon{margin-right:16px;color:#6e7a8a;font-size:1.33rem}.ibo-activity-entry--main-information-content{flex-grow:1;word-break:break-word}.ibo-activity-entry--main-information-content a{color:#2b6bb0}.ibo-activity-entry--main-information-content a:hover{color:#2a4265}.ibo-activity-entry--main-information-content a:active,.ibo-activity-entry--main-information-content a:focus{color:#2a4265}.ibo-activity-entry--sub-information{margin-top:4px;text-align:left;color:#6e7a8a}.ibo-activity-entry--sub-information>*:not(:last-child):after{content:" ";display:inline-block;vertical-align:middle;margin-left:0.5rem;margin-right:0.5rem;width:4px;height:4px;border-radius:100%;background-color:#929fb1}.ibo-activity-panel--load-more-entries-container{position:relative}.ibo-activity-panel--load-more-entries-container:hover .ibo-activity-panel--load-all-entries{margin-left:84px}.ibo-activity-panel--load-more-entries-container:not(:hover) .ibo-activity-panel--load-all-entries{visibility:hidden}.ibo-activity-panel--load-entries-button{width:32px;height:32px;border-radius:100%;background-color:#e1e7ec;border:1px solid #ccd4db}.ibo-activity-panel--load-more-entries{z-index:1}.ibo-activity-panel--load-all-entries{position:absolute;z-index:0;top:0;margin-left:0;transition:all 0.1s ease-in-out}.ibo-caselog-entry{}.ibo-caselog-entry .ibo-activity-entry--main-information{padding-top:12px;padding-bottom:12px}.ibo-caselog-entry .ibo-activity-entry--main-information-icon{display:none}.ibo-caselog-entry .ibo-activity-entry--main-information::before{content:"";position:absolute;top:0;bottom:0;width:3px}.ibo-caselog-entry:not(.ibo-is-current-user) .ibo-activity-entry--main-information::before{left:0;border-top-left-radius:5px;border-bottom-left-radius:5px}.ibo-caselog-entry:not(.ibo-is-current-user):last-child .ibo-activity-entry--main-information::before{border-bottom-left-radius:0}.ibo-caselog-entry.ibo-is-current-user .ibo-activity-entry--main-information::before{right:0;border-top-right-radius:5px;border-bottom-right-radius:5px}.ibo-caselog-entry.ibo-is-current-user:last-child .ibo-activity-entry--main-information::before{border-bottom-right-radius:0}.ibo-caselog-entry.ibo-is-closed.ibo-is-current-user .ibo-activity-entry--main-information::after{width:calc(100% - 3px)}.ibo-caselog-entry.ibo-is-closed:not(.ibo-is-current-user) .ibo-activity-entry--main-information::after{margin-left:3px}.ibo-caselog-entry--entry-for-caselog-1 .ibo-activity-entry--main-information::before{background-color:#689f38}.ibo-caselog-entry--entry-for-caselog-2 .ibo-activity-entry--main-information::before{background-color:#b83280}.ibo-caselog-entry--entry-for-caselog-3 .ibo-activity-entry--main-information::before{background-color:#f6ae55}.ibo-caselog-entry--entry-for-caselog-4 .ibo-activity-entry--main-information::before{background-color:#3182ce}.ibo-caselog-entry--entry-for-caselog-5 .ibo-activity-entry--main-information::before{background-color:#80deea}.ibo-caselog-entry--entry-for-caselog-6 .ibo-activity-entry--main-information::before{background-color:#c5e1a5}.ibo-caselog-entry--entry-for-caselog-7 .ibo-activity-entry--main-information::before{background-color:#fbb6ce}.ibo-transition-entry--original-state-label{color:#404b5a;text-decoration:line-through}a.ibo-edits-entry--short-description{position:relative;display:block;color:inherit}.ibo-edits-entry--long-description-toggler-icon{position:absolute;top:3px;right:0;transition:all 0.2s ease-in-out}.ibo-edits-entry--long-description{display:none;margin-top:8px;list-style:inside}.ibo-edits-entry:not(.ibo-is-closed) .ibo-edits-entry--long-description-toggler-icon{transform:rotateX(180deg)}.ibo-edits-entry:not(.ibo-is-closed) .ibo-edits-entry--long-description{display:block}a.ibo-notification-entry--short-description{color:inherit}.ibo-notification-entry--long-description-toggler-icon{margin-left:12px;transition:all 0.2s ease-in-out}.ibo-notification-entry--long-description{display:none;margin-top:8px;list-style:inside}.ibo-notification-entry:not(.ibo-is-closed) .ibo-notification-entry--long-description-toggler-icon{transform:rotateX(180deg)}.ibo-notification-entry:not(.ibo-is-closed) .ibo-notification-entry--long-description{display:block}.ibo-extension-details{display:inline-flex;flex-direction:row;justify-content:space-between;align-items:center;width:100%}.ibo-extension-details--information{flex-grow:1;display:flex;flex-direction:column}.ibo-extension-details--actions{display:flex}.ibo-extension-details--information--metadata{color:#6e7a8a}.ibo-extension-details--information--metadata span+span:before{content:"-";padding-left:4px;padding-right:4px}.ibo-extension-details:has(> .ibo-extension-details--actions input:is([type="checkbox"], [type="radio"]):checked)>.ibo-extension-details--information>.ibo-extension-details--information--label .ibo-badge.unchecked{display:none}.ibo-extension-details:has(> .ibo-extension-details--actions input[type="checkbox"]:not(:checked))>.ibo-extension-details--information>.ibo-extension-details--information--label .ibo-badge.checked,.ibo-extension-details:has(> .ibo-extension-details--actions input[type="radio"]:not(:checked))>.ibo-extension-details--information>.ibo-extension-details--information--label .ibo-badge.checked{display:none}.ibo-extension-details--actions>button{padding:3px 9px}.ibo-extension-details--actions:has(.toggler-install:not(:disabled)) .ibo-popover-menu--section a[data-resource-id="force_uninstall"],.ibo-extension-details--actions:has(.toggler-install:not(:disabled)) .ui-multiselect-checkboxes a[data-resource-id="force_uninstall"]{display:none}.ibo-extension-details .ibo-popover-menu~.ibo-button,.ibo-extension-details .ui-menu~.ibo-button,.ibo-extension-details .ui-dialog .ui-menu~.ui-button,.ui-dialog .ibo-extension-details .ui-menu~.ui-button,.ibo-extension-details .ui-menu~.ui-datepicker-current,.ibo-extension-details .ui-menu~.ui-datepicker-close,.ibo-extension-details .ui-multiselect-menu~.ibo-button,.ibo-extension-details .ui-dialog .ui-multiselect-menu~.ui-button,.ui-dialog .ibo-extension-details .ui-multiselect-menu~.ui-button,.ibo-extension-details .ui-multiselect-menu~.ui-datepicker-current,.ibo-extension-details .ui-multiselect-menu~.ui-datepicker-close,.ibo-extension-details .ibo-input-select-icon--menu~.ibo-button,.ibo-extension-details .ui-dialog .ibo-input-select-icon--menu~.ui-button,.ui-dialog .ibo-extension-details .ibo-input-select-icon--menu~.ui-button,.ibo-extension-details .ibo-input-select-icon--menu~.ui-datepicker-current,.ibo-extension-details .ibo-input-select-icon--menu~.ui-datepicker-close,.ibo-extension-details .graph_config .toolkit_menu.graph>ul>li ul~.ibo-button,.ibo-extension-details .graph_config .toolkit_menu.graph>ul>li .ui-dialog ul~.ui-button,.ui-dialog .ibo-extension-details .graph_config .toolkit_menu.graph>ul>li ul~.ui-button,.ibo-extension-details .graph_config .toolkit_menu.graph>ul>li ul~.ui-datepicker-current,.ibo-extension-details .graph_config .toolkit_menu.graph>ul>li ul~.ui-datepicker-close,.graph_config .toolkit_menu.graph>ul>li .ibo-extension-details ul~.ibo-button,.ibo-extension-details .ui-dialog .ibo-popover-menu~.ui-button,.ui-dialog .ibo-extension-details .ibo-popover-menu~.ui-button,.ibo-extension-details .ibo-popover-menu~.ui-datepicker-current,.ibo-extension-details .ibo-popover-menu~.ui-datepicker-close{visibility:hidden}.ibo-extension-details .ibo-popover-menu:has(.ibo-popover-menu--item)~.ibo-button,.ibo-extension-details .ibo-popover-menu:has(.ui-menu-item, .ui-multiselect-checkboxes li, .ibo-input-select-icon--menu--item, .graph_config .toolkit_menu.graph>ul>li ul li)~.ibo-button,.ibo-extension-details .ui-menu:has(.ui-menu-item, .ui-multiselect-checkboxes li, .ibo-input-select-icon--menu--item, .graph_config .toolkit_menu.graph>ul>li ul li)~.ibo-button,.ibo-extension-details .ui-dialog .ui-menu:has(.ui-menu-item, .ui-multiselect-checkboxes li, .ibo-input-select-icon--menu--item, .graph_config .toolkit_menu.graph>ul>li ul li)~.ui-button,.ui-dialog .ibo-extension-details .ui-menu:has(.ui-menu-item, .ui-multiselect-checkboxes li, .ibo-input-select-icon--menu--item, .graph_config .toolkit_menu.graph>ul>li ul li)~.ui-button,.ibo-extension-details .ui-menu:has(.ui-menu-item, .ui-multiselect-checkboxes li, .ibo-input-select-icon--menu--item, .graph_config .toolkit_menu.graph>ul>li ul li)~.ui-datepicker-current,.ibo-extension-details .ui-menu:has(.ui-menu-item, .ui-multiselect-checkboxes li, .ibo-input-select-icon--menu--item, .graph_config .toolkit_menu.graph>ul>li ul li)~.ui-datepicker-close,.ibo-extension-details .ui-multiselect-menu:has(.ui-menu-item, .ui-multiselect-checkboxes li, .ibo-input-select-icon--menu--item, .graph_config .toolkit_menu.graph>ul>li ul li)~.ibo-button,.ibo-extension-details .ui-dialog .ui-multiselect-menu:has(.ui-menu-item, .ui-multiselect-checkboxes li, .ibo-input-select-icon--menu--item, .graph_config .toolkit_menu.graph>ul>li ul li)~.ui-button,.ui-dialog .ibo-extension-details .ui-multiselect-menu:has(.ui-menu-item, .ui-multiselect-checkboxes li, .ibo-input-select-icon--menu--item, .graph_config .toolkit_menu.graph>ul>li ul li)~.ui-button,.ibo-extension-details .ui-multiselect-menu:has(.ui-menu-item, .ui-multiselect-checkboxes li, .ibo-input-select-icon--menu--item, .graph_config .toolkit_menu.graph>ul>li ul li)~.ui-datepicker-current,.ibo-extension-details .ui-multiselect-menu:has(.ui-menu-item, .ui-multiselect-checkboxes li, .ibo-input-select-icon--menu--item, .graph_config .toolkit_menu.graph>ul>li ul li)~.ui-datepicker-close,.ibo-extension-details .ibo-input-select-icon--menu:has(.ui-menu-item, .ui-multiselect-checkboxes li, .ibo-input-select-icon--menu--item, .graph_config .toolkit_menu.graph>ul>li ul li)~.ibo-button,.ibo-extension-details .ui-dialog .ibo-input-select-icon--menu:has(.ui-menu-item, .ui-multiselect-checkboxes li, .ibo-input-select-icon--menu--item, .graph_config .toolkit_menu.graph>ul>li ul li)~.ui-button,.ui-dialog .ibo-extension-details .ibo-input-select-icon--menu:has(.ui-menu-item, .ui-multiselect-checkboxes li, .ibo-input-select-icon--menu--item, .graph_config .toolkit_menu.graph>ul>li ul li)~.ui-button,.ibo-extension-details .ibo-input-select-icon--menu:has(.ui-menu-item, .ui-multiselect-checkboxes li, .ibo-input-select-icon--menu--item, .graph_config .toolkit_menu.graph>ul>li ul li)~.ui-datepicker-current,.ibo-extension-details .ibo-input-select-icon--menu:has(.ui-menu-item, .ui-multiselect-checkboxes li, .ibo-input-select-icon--menu--item, .graph_config .toolkit_menu.graph>ul>li ul li)~.ui-datepicker-close,.ibo-extension-details .graph_config .toolkit_menu.graph>ul>li ul:has(.ui-menu-item, .ui-multiselect-checkboxes li, .ibo-input-select-icon--menu--item, .graph_config .toolkit_menu.graph>ul>li ul li)~.ibo-button,.ibo-extension-details .graph_config .toolkit_menu.graph>ul>li .ui-dialog ul:has(.ui-menu-item, .ui-multiselect-checkboxes li, .ibo-input-select-icon--menu--item, .graph_config .toolkit_menu.graph>ul>li ul li)~.ui-button,.ui-dialog .ibo-extension-details .graph_config .toolkit_menu.graph>ul>li ul:has(.ui-menu-item, .ui-multiselect-checkboxes li, .ibo-input-select-icon--menu--item, .graph_config .toolkit_menu.graph>ul>li ul li)~.ui-button,.ibo-extension-details .graph_config .toolkit_menu.graph>ul>li ul:has(.ui-menu-item, .ui-multiselect-checkboxes li, .ibo-input-select-icon--menu--item, .graph_config .toolkit_menu.graph>ul>li ul li)~.ui-datepicker-current,.ibo-extension-details .graph_config .toolkit_menu.graph>ul>li ul:has(.ui-menu-item, .ui-multiselect-checkboxes li, .ibo-input-select-icon--menu--item, .graph_config .toolkit_menu.graph>ul>li ul li)~.ui-datepicker-close,.graph_config .toolkit_menu.graph>ul>li .ibo-extension-details ul:has(.ui-menu-item, .ui-multiselect-checkboxes li, .ibo-input-select-icon--menu--item, .graph_config .toolkit_menu.graph>ul>li ul li)~.ibo-button,.ibo-extension-details .ui-dialog .ibo-popover-menu:has(.ui-menu-item, .ui-multiselect-checkboxes li, .ibo-input-select-icon--menu--item, .graph_config .toolkit_menu.graph>ul>li ul li)~.ui-button,.ui-dialog .ibo-extension-details .ibo-popover-menu:has(.ui-menu-item, .ui-multiselect-checkboxes li, .ibo-input-select-icon--menu--item, .graph_config .toolkit_menu.graph>ul>li ul li)~.ui-button,.ibo-extension-details .ibo-popover-menu:has(.ui-menu-item, .ui-multiselect-checkboxes li, .ibo-input-select-icon--menu--item, .graph_config .toolkit_menu.graph>ul>li ul li)~.ui-datepicker-current,.ibo-extension-details .ibo-popover-menu:has(.ui-menu-item, .ui-multiselect-checkboxes li, .ibo-input-select-icon--menu--item, .graph_config .toolkit_menu.graph>ul>li ul li)~.ui-datepicker-close,.ibo-extension-details .ui-menu:has(.ibo-popover-menu--item)~.ibo-button,.ibo-extension-details .ui-dialog .ui-menu:has(.ibo-popover-menu--item)~.ui-button,.ui-dialog .ibo-extension-details .ui-menu:has(.ibo-popover-menu--item)~.ui-button,.ibo-extension-details .ui-menu:has(.ibo-popover-menu--item)~.ui-datepicker-current,.ibo-extension-details .ui-menu:has(.ibo-popover-menu--item)~.ui-datepicker-close,.ibo-extension-details .ui-multiselect-menu:has(.ibo-popover-menu--item)~.ibo-button,.ibo-extension-details .ui-dialog .ui-multiselect-menu:has(.ibo-popover-menu--item)~.ui-button,.ui-dialog .ibo-extension-details .ui-multiselect-menu:has(.ibo-popover-menu--item)~.ui-button,.ibo-extension-details .ui-multiselect-menu:has(.ibo-popover-menu--item)~.ui-datepicker-current,.ibo-extension-details .ui-multiselect-menu:has(.ibo-popover-menu--item)~.ui-datepicker-close,.ibo-extension-details .ibo-input-select-icon--menu:has(.ibo-popover-menu--item)~.ibo-button,.ibo-extension-details .ui-dialog .ibo-input-select-icon--menu:has(.ibo-popover-menu--item)~.ui-button,.ui-dialog .ibo-extension-details .ibo-input-select-icon--menu:has(.ibo-popover-menu--item)~.ui-button,.ibo-extension-details .ibo-input-select-icon--menu:has(.ibo-popover-menu--item)~.ui-datepicker-current,.ibo-extension-details .ibo-input-select-icon--menu:has(.ibo-popover-menu--item)~.ui-datepicker-close,.ibo-extension-details .graph_config .toolkit_menu.graph>ul>li ul:has(.ibo-popover-menu--item)~.ibo-button,.ibo-extension-details .graph_config .toolkit_menu.graph>ul>li .ui-dialog ul:has(.ibo-popover-menu--item)~.ui-button,.ui-dialog .ibo-extension-details .graph_config .toolkit_menu.graph>ul>li ul:has(.ibo-popover-menu--item)~.ui-button,.ibo-extension-details .graph_config .toolkit_menu.graph>ul>li ul:has(.ibo-popover-menu--item)~.ui-datepicker-current,.ibo-extension-details .graph_config .toolkit_menu.graph>ul>li ul:has(.ibo-popover-menu--item)~.ui-datepicker-close,.graph_config .toolkit_menu.graph>ul>li .ibo-extension-details ul:has(.ibo-popover-menu--item)~.ibo-button,.ibo-extension-details .ui-dialog .ibo-popover-menu:has(.ibo-popover-menu--item)~.ui-button,.ui-dialog .ibo-extension-details .ibo-popover-menu:has(.ibo-popover-menu--item)~.ui-button,.ibo-extension-details .ibo-popover-menu:has(.ibo-popover-menu--item)~.ui-datepicker-current,.ibo-extension-details .ibo-popover-menu:has(.ibo-popover-menu--item)~.ui-datepicker-close{visibility:visible}.ibo-extension-details .ibo-toggler--wrapper:has(.ibo-toggler.ibo-is-hidden){visibility:hidden}.ibo-bulk--bulk-modify--incompatible-attribute:before{margin-right:4px;content:"";color:#429ae1}#form_part_csv_options:has(#ibo-sanitize-excel-export--input:checked) #ibo-sanitize-excel-export--alert,#form_part_xlsx_options:has(#ibo-sanitize-excel-export--input:checked) #ibo-sanitize-excel-export--alert{display:none}.ibo-block-csv textarea{width:100%;min-height:10em;margin-top:10px}.ibo-block-list--empty-text,.ibo-block-list--create-action{text-align:center}.ibo-block-list--create-icon{margin-right:0.5rem}.ibo-linked-set--bulk-tooltip-info:before{margin-right:4px;content:"";color:#429ae1}.ibo-table-preview{margin-top:20px;overflow-x:auto}.ibo-table-preview th{position:relative;padding:4px 24px 4px 4px;border-width:1px 1px 0;border-style:groove groove none;background:#f2f2f2}.ibo-table-preview td{padding-right:4px;padding-left:4px;border-width:0 1px;border-style:none groove}.ibo-table-preview tr:last-child td{border-bottom-width:1px;border-bottom-style:groove}.ibo-preview-header{margin-bottom:4px}.ibo-table-preview--remove-column{position:absolute;top:8px;right:8px;display:inline-block;cursor:pointer;font-size:8px}#form_part_interactive_fields_xlsx,#form_part_interactive_fields_csv,#form_part_interactive_fields_pdf{margin-top:24px}.ibo-welcome-popup--dialog.ui-dialog-content{padding:0 0;height:auto !important;max-height:80vh !important}.ibo-welcome-popup--messages-stack{min-width:300px;max-width:300px;padding:24px 16px;overflow-y:auto;background-color:#f8f9fa}.ibo-welcome-popup--messages-stack>*:not(:first-child){margin-top:12px}.ibo-welcome-popup--stack-item{padding:12px 16px;background-color:white;border:1px solid #d5dde5}.ibo-welcome-popup--stack-item.ibo-is-active{border-color:#929fb1}.ibo-welcome-popup--stack-item.ibo-is-acknowledged{opacity:0.6}.ibo-welcome-popup--stack-item.ibo-is-acknowledged.ibo-is-active{opacity:1}.ibo-welcome-popup--stack-item-icon{width:32px;height:32px;min-width:32px;min-height:32px;margin-right:12px;border-width:1px}.ibo-welcome-popup--message-content-wrapper{overflow:auto}.ibo-welcome-popup--message-content{display:flex;justify-content:space-between;align-items:center;padding:32px 48px}.ibo-welcome-popup--message-content .ibo-welcome-popup--message-illustration{margin-left:48px}.ibo-welcome-popup--message-content:not(.ibo-is-active){display:none}.ibo-welcome-popup--message-content.ibo-is-illustration-on-left-side{flex-direction:row-reverse}.ibo-welcome-popup--message-content.ibo-is-illustration-on-left-side .ibo-welcome-popup--message-illustration{margin-left:unset;margin-right:48px}.ibo-welcome-popup--message-title{margin-bottom:32px}.ibo-welcome-popup--message-illustration{display:flex;min-width:256px;aspect-ratio:1;background-size:contain}.ibo-welcome-popup--message-illustration>svg{height:auto}.ibo-user-rights{padding:4px 12px;border-radius:4px}.ibo-user-rights.ibo-is-success{background-color:#dcedc8;color:#235816;border:1px solid #8ac34a}.ibo-user-rights.ibo-is-failure{background-color:#fce8e8;color:#491d1d;border:1px solid #f56565}:root{--ibo-dm-class--User--main-color: #546e7a;--ibo-dm-class--User--complementary-color: white}.ibo-dm-class--User{--ibo-main-color: #546e7a;--ibo-main-color--100: #eaeef0;--ibo-main-color--900: #1f292d;--ibo-complementary-color: white}.ibo-dm-class-alt--User{--ibo-main-color: white;--ibo-complementary-color: #546e7a}:root{--ibo-dm-enum--User-status-enabled--main-color: #689f38;--ibo-dm-enum--User-status-enabled--complementary-color: white}.ibo-dm-enum--User-status-enabled{--ibo-main-color: #689f38;--ibo-main-color--100: #edf6e5;--ibo-main-color--900: #253914;--ibo-complementary-color: white}.ibo-dm-enum-alt--User-status-enabled{--ibo-main-color: white;--ibo-complementary-color: #689f38}:root{--ibo-dm-enum--User-status-disabled--main-color: #f6ae55;--ibo-dm-enum--User-status-disabled--complementary-color: white}.ibo-dm-enum--User-status-disabled{--ibo-main-color: #f6ae55;--ibo-main-color--100: #fdefdd;--ibo-main-color--900: #492a04;--ibo-complementary-color: white}.ibo-dm-enum-alt--User-status-disabled{--ibo-main-color: white;--ibo-complementary-color: #f6ae55}:root{--ibo-dm-class--Action--main-color: #546e7a;--ibo-dm-class--Action--complementary-color: white}.ibo-dm-class--Action{--ibo-main-color: #546e7a;--ibo-main-color--100: #eaeef0;--ibo-main-color--900: #1f292d;--ibo-complementary-color: white}.ibo-dm-class-alt--Action{--ibo-main-color: white;--ibo-complementary-color: #546e7a}:root{--ibo-dm-enum--Action-status-enabled--main-color: #689f38;--ibo-dm-enum--Action-status-enabled--complementary-color: white}.ibo-dm-enum--Action-status-enabled{--ibo-main-color: #689f38;--ibo-main-color--100: #edf6e5;--ibo-main-color--900: #253914;--ibo-complementary-color: white}.ibo-dm-enum-alt--Action-status-enabled{--ibo-main-color: white;--ibo-complementary-color: #689f38}:root{--ibo-dm-enum--Action-status-disabled--main-color: #e1e7ec;--ibo-dm-enum--Action-status-disabled--complementary-color: #6e7a8a}.ibo-dm-enum--Action-status-disabled{--ibo-main-color: #e1e7ec;--ibo-main-color--100: #e9eef1;--ibo-main-color--900: #1e272f;--ibo-complementary-color: #6e7a8a}.ibo-dm-enum-alt--Action-status-disabled{--ibo-main-color: #6e7a8a;--ibo-complementary-color: #e1e7ec}:root{--ibo-dm-enum--Action-status-test--main-color: #f6ae55;--ibo-dm-enum--Action-status-test--complementary-color: white}.ibo-dm-enum--Action-status-test{--ibo-main-color: #f6ae55;--ibo-main-color--100: #fdefdd;--ibo-main-color--900: #492a04;--ibo-complementary-color: white}.ibo-dm-enum-alt--Action-status-test{--ibo-main-color: white;--ibo-complementary-color: #f6ae55}.ibo-about-box--top-part{display:flex;flex-direction:row;align-content:center}.ibo-about-box--top-part>div{padding:16px 12px;margin:auto auto;width:50%}:root{--ibo-body-text-color: #212934;--ibo-body-background-color: #f2f2f2}html{height:100vh}body{display:flex;height:100vh;color:var(--ibo-body-text-color);background-color:var(--ibo-body-background-color)}#ibo-navigation-menu{z-index:20}#ibo-page-container{position:relative;z-index:10;height:100%;overflow:auto;flex-grow:1;display:flex;flex-direction:column}#ibo-top-bar,#ibo-main-content{padding-left:36px;padding-right:36px}#ibo-top-container{z-index:20;position:sticky;top:0;left:0;right:0}#ibo-center-container{position:relative;z-index:10;flex-grow:1;overflow:hidden}#ibo-center-container>*{height:100%}#ibo-main-content{padding-top:16px;padding-bottom:16px;overflow:auto}#ibo-main-content>.ibo-panel{margin-left:auto;margin-right:auto}.ibo-preferences--user-preferences--picture-placeholder{display:flex;flex-direction:row;flex-wrap:wrap}.ibo-preferences--user-preferences--picture-placeholder--image{height:54px;width:54px;border-radius:100%;margin:12px;border:solid 3px #d5dde5}.ibo-preferences--user-preferences--picture-placeholder--image>img{border-radius:100%;background-color:#d5dde5}.ibo-preferences--user-preferences--picture-placeholder--image.ibo-is-active{border-color:#2c5382}.ibo-preferences--user-preferences--picture-placeholder--image:hover{border-color:#3182ce}#ibo-form-for-user-interface-preferences>.ibo-keyboard-shortcut--shortcut{display:table;width:100%}#ibo-form-for-user-interface-preferences>.ibo-keyboard-shortcut--shortcut>*:not(.ibo-button){width:30%;display:table-cell}.ibo-keyboard-shortcut--input,.ibo-keyboard-shortcut--input:focus{display:inline-block;width:auto;text-transform:capitalize;text-align:center;color:#404b5a;background-color:transparent;border:1px solid #aebecd;border-bottom:2px solid #aebecd;border-radius:3px;padding:2px 4px;margin-bottom:5px}.ibo-keyboard-shortcut--input.ibo-is-focus,.ibo-keyboard-shortcut--input:focus.ibo-is-focus{text-transform:none;color:#9c4221;border-color:#dd6c20}#ibo-favorite-organizations .ibo-toolbar{float:right;vertical-align:top}#ibo-favorite-organizations .ibo-datatable--toolbar{padding-top:3px}#ibo-attachment--upload-file .ibo-input-file-select--container{display:inline-block}.ibo-attachment--datatable--icon-preview{max-height:44px;max-width:44px}.ibo-attachment--datatable tbody tr td{vertical-align:middle}.ibo-attachment--upload-file--drop-zone-hint{display:none}.ibo-drag-in{border:2px #ccd4db dashed}.ibo-drag-in .ibo-attachment--upload-file--drop-zone-hint{display:flex;flex-direction:column;justify-content:center;align-items:center;width:100%;max-height:200px;margin:22px 0;color:#6e7a8a}.ibo-drag-in .ibo-attachment--upload-file--drop-zone-hint>svg{margin-bottom:5px}.ibo-drag-in #ibo-attachment--upload-file--upload-button-container{display:none}.ibo-tab-container--tab-header.ibo-drag-in,.ibo-drag-in.ibo-tab-container--extra-tabs-container{border:none;background-color:#bee3f8;color:#2c5382}.ibo-tab-container--tab-header.ibo-drag-in>a::after,.ibo-drag-in.ibo-tab-container--extra-tabs-container>a::after{content:"";padding-left:8px;color:#3182ce}.itop-simple-graph{margin-top:10px;border:1px dotted transparent;border-radius:5px}.itop-simple-graph.ibo-has-focus{border:1px dotted #404b5a}.graph_zoom{display:flex;float:right;align-items:center}.graph_zoom_slider{height:1.1em;display:inline-block;width:10em}.graph_zoom_plus,.graph_zoom_minus{cursor:pointer;display:inline-block;margin-left:0.5em;margin-right:0.5em}.graph_config{display:flex;align-items:center;flex-wrap:wrap}.graph_config .toolkit_menu.graph>ul>li{position:relative}.graph_config .toolkit_menu.graph>ul>li ul{z-index:1;position:absolute;display:none}.graph_separator{flex-grow:1}.ibo-simple-graph--grouping-threshold--container,.ibo-simple-graph--additional-context--container{margin-right:0.3em;display:flex;align-items:center}.ibo-simple-graph--grouping-threshold--container>*,.ibo-simple-graph--additional-context--container>*{margin-right:1em}#graph_grouping_threshold{width:auto;padding-right:0}.ibo-display-graph--search-box .sf_criterion_area{display:flex;flex-direction:column}.ibo-display-graph--search-box .sf_criterion_row{display:flex;flex-wrap:wrap;align-items:center}.ibo-display-graph--search-box .sf_criterion_row>div{align-items:center;display:flex;padding:0 15px}.ibo-display-graph--search-box .sf_criterion_row>div>input{margin-right:10px}.ibo-display-graph--search-box .sf_criterion_row>div .ibo-medallion-icon{display:flex;align-items:center}.ibo-display-graph--search-box #ReloadMovieBtn{align-self:flex-end}#impacted_objects_lists>div~div{margin-top:24px}#impacted_objects_lists_placeholder,#impacted_groups_placeholder{height:256px}.ibo-audit--audit-category--panel .ibo-panel--body tr.ibo-is-red td:last-of-type:before{background-color:#c53030}.ibo-audit--audit-category--panel .ibo-panel--body tr.ibo-is-orange td:last-of-type:before{background-color:#c05621}.ibo-audit--audit-category--panel .ibo-panel--body tr.ibo-is-green td:last-of-type:before{background-color:#558b2f}.ibo-audit--audit-category--panel .ibo-panel--body{padding:10px 16px}.ibo-audit--audit-category--panel .ibo-panel--body .ibo-datatable td:not(:nth-child(1)),.ibo-audit--audit-category--panel .ibo-panel--body .ibo-datatable th:not(:nth-child(1)){text-align:right;width:100px}.ibo-audit--audit-category--panel .ibo-panel--body .ibo-datatable--toolbar{display:none}.ibo-audit--audit-category--panel .ibo-panel--body tr td:last-of-type:before{content:"";height:12px;width:12px;border-radius:100%;display:inline-block;margin-right:5px;vertical-align:middle}.ibo-audit--dashboard{padding:18px 0}.ibo-dashboard--grid-row+.ibo-audit--error-alert{margin-top:24px}.ibo-audit--audit-line--csv-download{height:2.5em;vertical-align:middle}.ibo-data-synchro-source--replicas-status.ibo-is-grey{color:#212934;background-color:#ccd4db}.ibo-data-synchro-source--replicas-status.ibo-is-orange{color:#7b341e;background-color:#fbd38d}.ibo-data-synchro-source--replicas-status.ibo-is-bluegrey{color:#263238;background-color:#b0bec5}.ibo-data-synchro-source--replicas-status.ibo-is-red{color:#742a2a;background-color:#feb2b2}.ibo-data-synchro-source--replicas-status.ibo-is-blue{color:#2a4265;background-color:#bee3f8}.ibo-data-synchro-source--replicas-status.ibo-is-green{color:#33691e;background-color:#dcedc8}.ibo-data-synchro-source--replicas-status.ibo-is-cyan{color:#006164;background-color:#c9eef2}.ibo-data-synchro-source--replicas-status-separator{border-top:white}.ibo-data-synchro-source--replicas-status.ibo-is-light{opacity:0.5}.ibo-data-synchro-source--replicas-status.ibo-is-light:hover{opacity:1}.synoptics tr td{padding:10px;min-width:200px;vertical-align:middle;text-align:center}.synoptics tr td.arrow{min-width:100px;border-top:2px solid #fcfcfd}.ibo-data-synchro-source--replicas-status--warning{margin:0 5px 0 8px}.ibo-datamodel-viewer--details .ibo-datamodel-viewer--empty{display:flex;flex-direction:column;align-items:center}.ibo-datamodel-viewer--details .ibo-datamodel-viewer--empty svg{width:max(20%, 384px)}.ibo-datamodel-viewer--breadcrumb{margin:4px 0}.ibo-datamodel-viewer--breadcrumb .ibo-button,.ibo-datamodel-viewer--breadcrumb .ui-dialog .ui-button,.ui-dialog .ibo-datamodel-viewer--breadcrumb .ui-button,.ibo-datamodel-viewer--breadcrumb .ui-datepicker-current,.ibo-datamodel-viewer--breadcrumb .ui-datepicker-close{text-transform:none}.ibo-datamodel-viewer--classname{color:#546e7a}.ibo-datamodel-viewer--tag--category{color:#37474f}.ibo-datamodel-viewer--tag--category .ibo-object-details--tag-icon{color:#546e7a}.ibo-datamodel-viewer--icon--abstract:after{content:"A";display:inline-flex;justify-content:center;align-items:center;width:15px;height:15px;line-height:14px;border-radius:50%;border:1px solid #00bbd4;color:white;background-color:#00bbd4}.ibo-datamodel-viewer--parent--spacer{padding:0 8px}.ibo-datamodel-viewer--classes-list .selectize-input,.ibo-datamodel-viewer--classes-list .ibo-quick-create--input.selectize-control.single .selectize-input.input-active,.ibo-quick-create--input.selectize-control.single .ibo-datamodel-viewer--classes-list .selectize-input.input-active{background-color:white !important;background-image:none !important;color:#404b5a;box-shadow:none !important;border-color:#aebecd !important}#ibo-datamodel-viewer--attributes-table>tbody tr td:first-child{width:3px}.ibo-datamodel-viewer--origin-cell{vertical-align:middle}.ibo-datamodel-viewer--origin-cell>div{height:8px;width:8px;border-radius:100%}.ibo-datamodel-viewer--classes-list{position:relative;height:100%;width:384px;padding-left:24px;padding-top:8px;overflow-y:scroll}.ibo-datamodel-viewer--lifecycle--code{color:#6e7a8a}.ibo-datamodel-viewer--lifecycle--stimuli{color:#2a4265}.ibo-datamodel-viewer--lifecycle--attribute-option{color:#702459}.dataModelSchema g{cursor:pointer}.dataModelSchema g:hover rect:not(.liseret){fill:#ccd4db}.dataModelSchema text{fill:#212934;text-anchor:middle}#selfreferencing:hover~g>.selfattr{fill:#ccd4db}.tooltipD3{position:fixed;text-align:center;background:white;border:1px solid #6e7a8a;border-radius:3px;pointer-events:none;fill:#212934;text-anchor:middle}.tooltipD3 i{font-size:1rem}.tooltipD3 span{margin:3px}#tooltipD3_top{border-bottom:1px solid #6e7a8a;padding:3px}.ibo-datamodel-viewer--lifecycle-image{margin-bottom:16px}#tabs1-import .ibo-field--label{max-width:50%}div.ibo-csv-import--cell-modified{font-weight:bold;color:#2b6bb0}div.ibo-csv-import--cell-error{font-weight:bold;color:#c53030}div.ibo-csv-import--cell-message{padding-top:3px}tr.ibo-csv-import--row-unchanged td{border-bottom:1px #ccd4db solid}.wizContainer table tr.ibo-csv-import--row-error td{border-bottom:1px #ccd4db solid;background-color:#fed7d7}tr.ibo-csv-import--row-modified td{border-bottom:1px #ccd4db solid}tr.ibo-csv-import--row-added td{border-bottom:1px #ccd4db solid}.ibo-csv-import--download-file{font-size:4em;color:#f6ae55;margin:20px}.ibo-global-search--result--title>img{max-height:48px;max-width:48px;margin-right:8px}.ibo-run-query--highlight{background-color:#fbd38d}.ibo-oauth-wizard .ibo-panel--body .ibo-oauth-wizard--form--container{display:flex;flex-direction:row;flex-grow:1}.ibo-oauth-wizard .ibo-panel--body .ibo-oauth-wizard--illustration svg{max-height:384px}#ibo-oauth-wizard--conf--result{white-space:pre-wrap}.ibo-notifications--view-all--container{display:grid;grid-gap:24px}.ibo-notifications--view-all--container .ibo-object-summary .ibo-panel--title{font-size:1.5rem}.ibo-notifications--view-all--container .ibo-object-summary .ibo-panel--toolbar{min-width:96px}.ibo-notifications--view-all--container .ibo-object-summary>.ibo-panel--body{box-shadow:none;max-height:400px}.ibo-notifications--view-all--container .ibo-object-summary+.ibo-object-summary{margin-top:0}@media screen and (max-width:768px){.ibo-notifications--view-all--container{grid-template-columns:repeat(1, 1fr)}}@media screen and (min-width:1024px){.ibo-notifications--view-all--container{grid-template-columns:repeat(2, 1fr)}}@media screen and (min-width:1408px){.ibo-notifications--view-all--container{grid-template-columns:repeat(3, 1fr)}}.ibo-notifications--view-all--toolbar{justify-content:space-between}.ibo-notifications--view-all--toggler{display:flex;align-content:center}.ibo-notifications--view-all--item--read .ibo-panel--body::before{background-color:#e1e7ec}.ibo-notifications--view-all--item--unread .ibo-panel--body::before{background-color:#e53e3e}.ibo-notifications--view-all--container .ibo-notifications--view-all--read-action,.ibo-notifications--view-all--container .ibo-notifications--view-all--unread-action{margin-left:0 !important}.ibo-notifications--view-all--item--read .ibo-notifications--view-all--read-action{display:none}.ibo-notifications--view-all--item--unread .ibo-notifications--view-all--unread-action{display:none}.ibo-notifications--view-all--empty{flex-direction:column;margin-top:96px}.ibo-notifications--view-all--empty svg{max-width:30%;height:auto}.ibo-input-select--notification-item{display:flex !important;flex-direction:row}.ibo-input-select--notification-item--mixed-value{font-size:1rem;color:#9c4221;margin-left:4px}.ibo-alert+.ibo-alert{margin-top:4px}.ibo-alert+.ibo-block:not(.ibo-alert){margin-top:16px}.ibo-button+.ibo-button,.ui-dialog .ui-button+.ibo-button,.ui-dialog .ui-button+.ui-button,.ui-dialog .ui-button+.ui-datepicker-current,.ui-dialog .ui-button+.ui-datepicker-close,.ui-datepicker-current+.ibo-button,.ui-dialog .ui-datepicker-current+.ui-button,.ui-datepicker-current+.ui-datepicker-current,.ui-datepicker-current+.ui-datepicker-close,.ui-datepicker-close+.ibo-button,.ui-dialog .ui-datepicker-close+.ui-button,.ui-datepicker-close+.ui-datepicker-current,.ui-datepicker-close+.ui-datepicker-close,.ui-dialog .ibo-button+.ui-button,.ibo-button+.ui-datepicker-current,.ibo-button+.ui-datepicker-close{margin-left:4px}.ibo-button-group+.ibo-button-group,.ibo-button+.ibo-button-group,.ui-dialog .ui-button+.ibo-button-group,.ui-datepicker-current+.ibo-button-group,.ui-datepicker-close+.ibo-button-group,.ibo-button-group+.ibo-button,.ui-dialog .ibo-button-group+.ui-button,.ibo-button-group+.ui-datepicker-current,.ibo-button-group+.ui-datepicker-close{margin-left:4px}.ibo-collapsible-section+.ibo-collapsible-section{margin-top:12px}.ibo-collapsible-section+.ibo-block:not(.ibo-collapsible-section){margin-top:16px}.ibo-caselog-list .ibo-collapsible-section{margin:0;min-width:22em}.ibo-caselog-list .ibo-collapsible-section .ibo-collapsible-section--body{color:#212934;padding:8px;background-color:rgba(248, 249, 250, 0.5)}.ibo-alert--body .ibo-collapsible-section .ibo-collapsible-section--body{color:#212934;padding:8px}.ibo-alert--body>*+.ibo-collapsible-section{margin-top:8px}.ibo-datatable+.ibo-block{margin-top:4px}.ibo-panel .ibo-panel--body .ibo-datatable{width:100%}.display_block+.display_block{margin-top:24px}.display_block+.ibo-block:not(.display_block){margin-top:16px}.ibo-field+.ibo-field:not(:empty){margin-top:16px}.form_field+.form_field{margin-top:16px}.ibo-fieldset+.ibo-field,fieldset+.ibo-field{margin-top:32px}.ibo-field+.ibo-fieldset:not(.ibo-column),.ibo-field+fieldset:not(.ibo-column){margin-top:32px}.ibo-fieldset+.ibo-fieldset:not(.ibo-column),fieldset+.ibo-fieldset:not(.ibo-column),.ibo-fieldset+fieldset:not(.ibo-column){margin-top:48px}.ibo-multi-column+.ibo-fieldset,.ibo-multi-column+fieldset{margin-top:48px}.ibo-form+.ibo-form{margin-top:24px}select+label,label+select,label>select,input+label,label+input,label>input{margin-left:8px}.ibo-datatable .attribute-set .attribute-set-item{display:inline;margin:0;padding:4px 6px;box-shadow:0 1px 2px rgba(0, 0, 0, 0.25), 0 1px 3px rgba(0, 0, 0, 0.12)}.ibo-datatable .attribute-set .attribute-set-item+.attribute-set-item{margin-left:0.5rem}.ibo-object-details.ibo-has-medallion-icon>.ibo-panel--body>.ibo-tab-container:not(.ibo-is-vertical)>.ibo-tab-container--tabs-list{padding-left:calc(32px + 96px + 32px - 24px)}.tippy-box[data-theme~="object-summary"]{background-color:rgba(255, 255, 255, 0);color:#212934}.tippy-box[data-theme~="object-summary"] .tippy-arrow{display:none}.ibo-panel+.ibo-panel{margin-top:24px}.ibo-panel+.ibo-block:not(.ibo-panel){margin-top:16px}#ibo-main-content{}#ibo-main-content .ibo-panel.ibo-has-sticky-header{margin-bottom:200px}#ibo-main-content .ibo-panel.ibo-has-sticky-header>.ibo-sticky-sentinel-top{top:-16px;height:16px}#ibo-main-content .ibo-panel.ibo-has-sticky-header>.ibo-panel--header.ibo-is-sticking,#ibo-main-content .ibo-panel.ibo-has-sticky-header>.ibo-is-sticking.ibo-object-summary--header{top:-16px}.ui-dialog-content{}.ui-dialog-content .ibo-panel.ibo-has-sticky-header{}.ui-dialog-content .ibo-panel.ibo-has-sticky-header>.ibo-sticky-sentinel-top{top:-16px;height:16px}.ui-dialog-content .ibo-panel.ibo-has-sticky-header>.ibo-panel--header.ibo-is-sticking,.ui-dialog-content .ibo-panel.ibo-has-sticky-header>.ibo-is-sticking.ibo-object-summary--header{top:-16px}.ibo-pill:not(:last-child){margin-right:16px}.ibo-dashboard--grid-row .ibo-dashlet-header-static{margin-top:12px}.ibo-dashboard--grid-row:first-child .ibo-dashlet:first-child .ibo-dashlet-header-static{margin-top:0}.ibo-details .ibo-prop--apply>span,.ibo-details .ibo-prop--cancel>span{display:unset}.ibo-details .ibo-prop--apply{display:table-column}.ibo-activity-panel--tab-entry-form .ibo-caselog-entry-form{padding-bottom:14px;border-bottom:1px solid #aebecd}.ibo-panel{}.ibo-panel>.ibo-panel--body>.ibo-tab-container{margin-top:-24px;margin-left:-16px;margin-right:-16px;margin-bottom:-24px}.ibo-panel>.ibo-panel--body>.ibo-tab-container>.ibo-tab-container--tab-container-list{height:100%;overflow-y:auto;flex-grow:1}.ibo-panel>.ibo-panel--body>.ibo-tab-container.ibo-is-vertical{display:flex;flex-direction:row}.ibo-panel>.ibo-panel--body>.ibo-tab-container.ibo-is-vertical>.ibo-tab-container--tabs-list{padding-top:48px;flex-direction:column;height:auto;padding-left:unset;margin-right:unset;min-width:calc(32px + 90px + 32px)}.ibo-panel>.ibo-panel--body>.ibo-tab-container.ibo-is-vertical>.ibo-tab-container--tabs-list>.ibo-tab-container--tab-header,.ibo-panel>.ibo-panel--body>.ibo-tab-container.ibo-is-vertical>.ibo-tab-container--tabs-list>.ibo-tab-container--extra-tabs-container{height:48px;width:100%;justify-content:left}.ibo-panel>.ibo-panel--body>.ibo-tab-container.ibo-is-vertical>.ibo-tab-container--tabs-list>.ibo-tab-container--tab-header>.ibo-tab-container--tab-toggler,.ibo-panel>.ibo-panel--body>.ibo-tab-container.ibo-is-vertical>.ibo-tab-container--tabs-list>.ibo-tab-container--extra-tabs-container>.ibo-tab-container--tab-toggler,.ibo-panel>.ibo-panel--body>.ibo-tab-container.ibo-is-vertical>.ibo-tab-container--tabs-list>.ibo-tab-container--tab-header>.ibo-tab-container--extra-tabs-list-toggler,.ibo-panel>.ibo-panel--body>.ibo-tab-container.ibo-is-vertical>.ibo-tab-container--tabs-list>.ibo-tab-container--extra-tabs-container>.ibo-tab-container--extra-tabs-list-toggler{width:100%;justify-content:left}.ibo-panel>.ibo-panel--body>.ibo-tab-container.ibo-is-vertical>.ibo-tab-container--tab-container{flex-grow:1;margin-left:unset}.ibo-panel.ibo-has-sticky-header>.ibo-panel--body>.ibo-tab-container>.ibo-tab-container--tabs-list.ibo-is-sticking{position:fixed;z-index:10}.ibo-panel.ibo-has-sticky-header>.ibo-panel--body>.ibo-tab-container:not(.ibo-is-vertical)>.ibo-tab-container--tabs-list.ibo-is-sticking{padding-left:0}.ibo-panel.ibo-has-sticky-header>.ibo-panel--body>.ibo-tab-container:not(.ibo-is-vertical)>.ibo-tab-container--tabs-list.ibo-is-sticking .ibo-tab-container--tab-toggler,.ibo-panel.ibo-has-sticky-header>.ibo-panel--body>.ibo-tab-container:not(.ibo-is-vertical)>.ibo-tab-container--tabs-list.ibo-is-sticking .ibo-tab-container--extra-tabs-list-toggler,.ibo-panel.ibo-has-sticky-header>.ibo-panel--body>.ibo-tab-container:not(.ibo-is-vertical)>.ibo-tab-container--tabs-list.ibo-is-sticking .ibo-tab-container--extra-tabs-list-toggler{font-size:1rem}.ibo-block-list--medallion{flex-direction:column;align-items:center}.ibo-block-list--medallion>.ibo-medallion-icon--image{margin:0 auto}.ibo-block-list--medallion>.ibo-medallion-icon--image~.ibo-medallion-icon--description{margin-top:12px}.ibo-block-list--medallion>.ibo-medallion-icon--description{flex-grow:1;text-align:center}.ibo-datatable .ibo-field-badge{margin:0;padding:0;color:unset;background-color:unset}.ibo-datatable .ibo-field-badge::before{content:"";display:inline-flex;margin-right:0.5rem;width:10px;height:10px;min-width:10px;min-height:10px;background-color:var(--ibo-main-color)}.ibo-datatable .ibo-field-badge .ibo-field-badge--decoration{display:none}.ibo-datatable .ibo-field-badge .ibo-field-badge--decoration+.ibo-field-badge--label{margin-left:unset}.ui-dialog .blockUI.blockOverlay{background-color:white}.ibo-datatable .blockUI.blockOverlay{background-color:white}.ibo-datatable .blockUI.blockMsg{font-size:2em}.ibo-badge+.ibo-badge{margin-left:4px}.ibo-extension-details+.ibo-extension-details,.ibo-extension-details--information--description .ibo-extension-details{margin-top:8px}.ibo-svg-illustration--container>svg *[fill="#6c63ff"]{fill:#ea7d1e}.ibo-navigation-menu.ibo-is-active .ibo-navigation-menu--drawer{transform:translate3d(0, 0, 0)}.switch{position:relative;display:inline-block;width:36px;height:20px;vertical-align:baseline}.switch input{display:none}.slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#929fb1;transition:0.4s}.slider:before{position:absolute;content:"";height:15px;width:15px;left:3px;bottom:3px;background-color:#d5dde5;transition:0.4s}input:checked+.slider{background-color:#dd6c20}input:focus+.slider{box-shadow:0 0 1px #dd6c20}input:checked+.slider:before{transform:translateX(14.5px)}.slider.round{border-radius:20px}.slider.round:before{border-radius:7px}.ibo-is-html-content blockquote{color:#212934}.center{text-align:center}.hidden{display:none}@keyframes progress_bar_color_ongoing{from{background-color:#FBD38D}to{background-color:#FEEBC8}}@-webkit-keyframes bg-pan-left{0%{background-position:100% 50%}100%{background-position:0 50%}}@keyframes bg-pan-left{0%{background-position:100% 50%}100%{background-position:0 50%}}body{display:flex;flex-direction:column;background-color:#f8f9fa;color:#212934;margin:0;padding:0;font-size:10pt;font-family:Tahoma, Verdana, Arial, Helvetica, serif;overflow-y:auto}h1{color:#555555;font-size:16pt}h2{color:#212934;font-size:14pt;font-weight:normal}h3{color:#1C94C4;font-size:12pt;font-weight:bold}a{color:#1c94c4;text-decoration:none}a:hover{color:#EA7D1E}.itop-setup--message{margin-top:16px}.next{width:100%;text-align:right}.v-spacer{padding-top:1em}button{margin-top:1em;padding-left:1em;padding-right:1em}p.info{padding-left:50px;background:url(../images/info-mid.png) no-repeat left -5px;min-height:48px}p.ok{padding-left:50px;background:url(../images/clean-mid.png) no-repeat left -8px;min-height:48px}p.warning{padding-left:50px;background:url(../images/messagebox_warning-mid.png) no-repeat left -5px;min-height:48px}p.error{padding-left:50px;background:url(../images/stop-mid.png) no-repeat left -5px;min-height:48px}label{cursor:pointer}td.label{text-align:left}label.read-only{color:#666;cursor:text}td.input{text-align:left}table.formTable{border:0}.wizlabel,.wizinput{color:#000;font-size:10pt}.wizhelp{color:#333;font-size:8pt}#progress{border:none;width:210px;height:26px;line-height:26px;text-align:center;margin:5px;box-shadow:inset 0 2px 4px 0 rgba(0, 0, 0, 0.06) !important;border-radius:2px;background-color:#EDF2F7 !important}#progress .progress{color:#000000 !important;background-image:linear-gradient(270deg, #FBD38D 50%, #FEEBC8 55%, #FBD38D 80%) !important;animation:bg-pan-left 3s infinite both;background-size:600% 100%;border-radius:inherit}#progress .progress.progress-error{background-image:none !important;background-color:#F56565 !important;animation:none}h3.clickable{background:url(../images/plus.gif) no-repeat left;padding-left:16px;cursor:hand}h3.clickable.open{background:url(../images/minus.gif) no-repeat left;padding-left:16px;cursor:hand}.message{color:#1A202C;background-color:#F7FAFC;border-left:4px solid #4A5568;padding:10px;font-size:initial}.message>.message-title{font-weight:bold;margin-right:5px}.message.message-valid{color:#276749;background-color:#F0FFF4;border-color:#48BB78}.message.message-warning{color:#C05621;background-color:#FFFAF0;border-color:#ED8936}.message.message-error{color:#C53030;background-color:#FFF5F5;border-color:#E53E3E}*:not(.message)+.message{margin-top:6px}.text-valid{color:#276749}.text-warning{color:#C05621}.text-error{color:#C53030}fieldset{border:none;padding:0;margin:15px 0 0 0}fieldset>legend{margin-bottom:7px;padding-bottom:7px;width:100%;color:#3C3C3C;font-size:11pt;font-weight:bold;border-bottom:1px solid #D2D2D2}.module-selection-banner img{max-height:48px}.module-selection-body{overflow:auto;box-shadow:inset 0 2px 4px 0 rgba(0, 0, 0, 0.06) !important;background-color:#F7FAFC;padding:10px}.module-selection-body .wiz-choice:not(:checked)~label .checked{display:none}.module-selection-body .wiz-choice:checked~label .unchecked{display:none}.ibo-extension-details:has(> .ibo-extension-details--actions>input:checked) .ibo-extension-details:has(#itop-ticket-mgmt-simple-ticket-enhanced-portal:not(:checked), #itop-ticket-mgmt-itil-enhanced-portal:not(:checked)) .ibo-extension-details--information--description::after{content:"Legacy portal is no longer part of iTop, by leaving this option unchecked your portal users won't be able to access iTop anymore.";display:block;margin-top:0.5em;font-weight:bold;color:#e60000b8}.ibo-extension-details--information--metadata{color:#404b5a}.choice-disabled{color:#6e7a8a}body{font-size:1.17rem;font-family:"Raleway"}#ibo_setup_container{width:800px;margin-left:auto;margin-right:auto;height:100%;display:flex;flex-direction:column;padding:20px 0}#ibo_setup_container pre{white-space:pre-wrap}#ibo_setup_container .ibo-title h2{margin-bottom:15px}#ibo_setup_container .ibo-setup--header{background-color:#fff;padding:0 20px;border:3px solid #ccd4db;height:80px;border-bottom:none;border-radius:3px 3px 0 0}#ibo_setup_container .ibo-setup--header .ibo-title--icon{border:0;vertical-align:middle;margin-right:20px}#ibo_setup_container .ibo-setup--body{display:flex;flex-direction:column;background-color:#fff;padding:20px;border:3px solid #ccd4db;border-top:none;flex-grow:1;overflow:auto;border-radius:0 0 3px 3px}#ibo_setup_container .ibo-setup--body .ibo-setup--wizard{width:100%;display:flex;flex-direction:column;height:100%}#ibo_setup_container .ibo-setup--body .ibo-setup--wizard .ibo-setup--wizard--content{overflow:auto}#ibo_setup_container .ibo-setup--body .ibo-setup--wizard .ibo-setup--wizard--buttons-container{margin-top:auto}#ibo_setup_container .ibo-setup--body .ibo-setup--wizard .ibo-setup--wizard--buttons-container tr{display:flex;justify-content:flex-end}#ibo_setup_container .ibo-setup--body .ibo-setup--wizard .ibo-setup--wizard--buttons-container button{margin-left:8px}#ibo_setup_container .ibo-setup--body .itop-setup--message{margin-top:16px}#ibo_setup_container .ibo-setup--body .ibo-setup--button-bar{margin-top:16px}#ibo_setup_container .ibo-setup--body .ibo-setup--button-bar .ibo-setup--button-spacer{flex-grow:1}#ibo_setup_container .ibo-setup--body .ibo-setup--js-error{overflow:auto;max-height:100px;color:#9b2c2c;font-size:1rem}#ibo_setup_container .ibo-setup--body .ibo-setup--upgrade-info{margin-top:5px}#ibo_setup_container .ibo-setup--body .ibo-fieldset,#ibo_setup_container .ibo-setup--body fieldset{margin-top:12px}#ibo_setup_container .ibo-setup--body .ibo-fieldset~.ibo-fieldset,#ibo_setup_container .ibo-setup--body fieldset~.ibo-fieldset,#ibo_setup_container .ibo-setup--body .ibo-fieldset~fieldset,#ibo_setup_container .ibo-setup--body fieldset~fieldset{margin-top:12px}#ibo_setup_container .ibo-setup--body .ibo-field{margin-top:5px}#ibo_setup_container .ibo-setup--body .ibo-setup--small-field-label .ibo-field--label{width:15%}#ibo_setup_container .ibo-setup--body .ibo-field--comments{font-size:1rem;color:#6e7a8a;text-align:left;width:100%;padding-left:10px}#ibo_setup_container .ibo-setup--body .ibo-alert{padding:7px 20px}#ibo_setup_container .ibo-setup--body .ibo-setup--small-message{font-size:1rem;color:#6e7a8a}#ibo_setup_container .ibo-setup--body .ibo-collapsible-section{margin:10px 0 0 0}#ibo_setup_container .ibo-setup--body .ibo-collapsible-section.ibo-setup--small .ibo-collapsible-section--header .ibo-collapsible-section--title{font-size:1.17rem;font-weight:400;color:#6e7a8a}#ibo_setup_container .ibo-setup--body .ibo-collapsible-section .ibo-collapsible-section--body{max-height:400px;overflow:auto}#ibo_setup_container .ibo-setup--body .ibo-input,#ibo_setup_container .ibo-setup--body .ui-autocomplete-input,#ibo_setup_container .ibo-setup--body .ui-multiselect,#ibo_setup_container .ibo-setup--body .dataTables_length select,.dataTables_length #ibo_setup_container .ibo-setup--body select,#ibo_setup_container .ibo-setup--body .ui_tpicker_hour_slider>select,#ibo_setup_container .ibo-setup--body .ui_tpicker_minute_slider>select,#ibo_setup_container .ibo-setup--body .ui_tpicker_second_slider>select,#ibo_setup_container .ibo-setup--body select.ibo-input-select-placeholder,#ibo_setup_container .ibo-setup--body .ibo-datatableconfig--attributes-panel--per-page--input,#ibo_setup_container .ibo-setup--body .search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content input[type="text"],.search_form_handler .sf_criterion_area .search_form_criteria .sfc_form_group .sfc_fg_operators .sfc_fg_operator .sfc_op_content #ibo_setup_container .ibo-setup--body input[type="text"],#ibo_setup_container .ibo-setup--body .search_form_handler .sf_filter .sff_input_wrapper input[type="text"],.search_form_handler .sf_filter .sff_input_wrapper #ibo_setup_container .ibo-setup--body input[type="text"]{width:auto;display:inline-block}#ibo_setup_container .ibo-setup--body table td{white-space:nowrap;line-height:2.5rem;padding-right:8px;padding-bottom:1rem}#ibo_setup_container .ibo-setup--body .setup-content-title,#ibo_setup_container .ibo-setup--body h2{margin-bottom:18px}.ibo-setup--button-bar{margin-top:16px}.ibo-setup--button-bar .ibo-setup--full-width{width:100%}.ibo-setup--button-bar .ibo-setup--full-width{width:100%}.ibo-setup-summary-title,.ibo-setup-summary-title:visited,.ibo-setup-summary-title:hover{font-size:1.17rem;color:inherit}#ibo-setup-licenses--components-list{background-color:#f2f2f2;padding:12px;box-shadow:inset 0px 2px 4px 1px rgba(0, 0, 0, 0.15)}.setup-prefix-toggler--input--container,.setup-tls--input--container,.setup-disk-location--input--container,.setup-backup--input--container{display:flex;line-height:2.5rem;margin:1rem 0}.setup-prefix-toggler--input--container input,.setup-tls--input--container input,.setup-disk-location--input--container input,.setup-backup--input--container input{margin:0 8px}.setup-disk-location--input--container input,.setup-backup--input--container input{flex-grow:1}.collapsable-options{margin-bottom:18px}.collapsable-options [data-role="setup-collapsable-options--toggler"]::before{margin-right:8px;cursor:pointer}.collapsable-options:not(.setup-is-opened) [data-role="setup-collapsable-options--toggler"]::before{content:""}.collapsable-options.setup-is-opened [data-role="setup-collapsable-options--toggler"]::before{content:""}.setup-input--hint--icon{color:#6e7a8a}.setup-invalid-field--icon{color:#c53030;margin-left:8px}.setup-accept-licenses{margin-top:18px}.module-selection-banner{display:flex}.module-selection-banner>img{margin-right:12px}.setup-end-placeholder{display:flex;flex-direction:row;align-items:center}.setup-end-placeholder>div{padding:0px 15px}.setup-end-placeholder a{display:flex;flex-direction:column;align-items:center}.setup-end-placeholder a svg{max-height:150px;margin-bottom:15px;width:auto}.setup-extension--icon{margin-right:5px;color:#2b6bb0;font-size:1.33rem}.setup-extension--missing .setup-extension--icon{color:#a00000}.setup-extension-tag{display:inline-flex;background-color:grey;border-radius:8px;padding-left:3px;padding-right:3px;margin-right:3px}.setup-extension-tag.installed{background-color:#9eff9e}.setup-extension-tag.notinstalled{background-color:#ed9eff}.setup-extension-tag.tobeinstalled{background-color:#9ef0ff}.setup-extension-tag.tobeuninstalled{background-color:#ff9e9e}.setup-extension-tag.notuninstallable{background-color:#ffc98c}.setup-extension-tag.removed{background-color:#969594}.ibo-extension-details{align-items:flex-start}.ibo-extension-details--actions input{margin:0.2em 0.5em;width:12px}:not(.ibo-badge)~.ibo-badge{margin-left:0.5em}.ibo-extension-details--information--label i{font-size:0.9em;margin-left:0.3em}.setup--wizard-choice--label+.setup--wizard-choice--more-info{margin-left:0.5rem}#params_summary{overflow:auto}#params_summary div{width:100%;margin-top:0;padding-top:0.5em;padding-left:0}#params_summary div ul{margin-left:0;padding-left:40px}#params_summary div.closed ul{display:none}#params_summary div li{list-style:none;width:100%;margin-left:0;padding-left:0em}.title{padding-left:20px;font-weight:bold;cursor:pointer}#params_summary div.closed .title::before{margin-right:5px;content:""}#params_summary div:not(.closed) .title::before{margin-right:5px;content:""}#progress_content *:not(.message)+.message{margin-top:1.5rem}#fresh_content{border:0;min-height:300px;min-width:600px;display:none;margin-left:auto;margin-right:auto} \ No newline at end of file diff --git a/css/setup.scss b/css/setup.scss index 7c2968cd25..421f21bf19 100644 --- a/css/setup.scss +++ b/css/setup.scss @@ -316,29 +316,34 @@ fieldset { background-color: #F7FAFC; padding: 10px; .wiz-choice{ - &:checked ~ .description { - #itop-ticket-mgmt-simple-ticket-enhanced-portal:not(:checked), - #itop-ticket-mgmt-itil-enhanced-portal:not(:checked) { - ~ .description::after { - content: "Legacy portal is no longer part of iTop, by leaving this option unchecked your portal users won't be able to access iTop anymore."; - display: block; - margin-top: 0.5em; - font-weight: bold; - color: $legacy-portal-removal-text-color; - } - } - } - &:not(:checked) ~ label .setup-extension-tag.checked{ + &:not(:checked) ~ label .checked{ display:none; } - &:checked ~ label .setup-extension-tag.unchecked{ + &:checked ~ label .unchecked{ display:none; } } } +.ibo-extension-details:has(>.ibo-extension-details--actions>input:checked) { + .ibo-extension-details:has(#itop-ticket-mgmt-simple-ticket-enhanced-portal:not(:checked), #itop-ticket-mgmt-itil-enhanced-portal:not(:checked)) { + .ibo-extension-details--information--description::after { + content: "Legacy portal is no longer part of iTop, by leaving this option unchecked your portal users won't be able to access iTop anymore."; + display: block; + margin-top: 0.5em; + font-weight: bold; + color: $legacy-portal-removal-text-color; + } + } +} +.ibo-extension-details--information--metadata{ + color: $ibo-color-grey-800; +} +.choice-disabled { + color: $ibo-color-grey-700; +} body { font-size: 1.17rem; @@ -522,10 +527,12 @@ body { } } -.ibo-setup-summary-title { - font-size: $ibo-font-size-150; +.ibo-setup-summary-title, .ibo-setup-summary-title:visited, .ibo-setup-summary-title:hover { + font-size: $ibo-font-size-150; + color: inherit; } + #ibo-setup-licenses--components-list { background-color: $ibo-color-white-200; padding: 12px; @@ -605,6 +612,7 @@ body { color:#a00000; } .setup-extension-tag { + display: inline-flex; background-color: grey; border-radius: 8px; padding-left: 3px; @@ -630,6 +638,21 @@ body { } } +.ibo-extension-details { + align-items: flex-start; +} +.ibo-extension-details--actions input{ + margin:0.2em 0.5em; + width: 12px; +} +:not(.ibo-badge) ~ .ibo-badge{ + margin-left:0.5em; +} +.ibo-extension-details--information--label i{ + font-size : 0.9em; + margin-left:0.3em; +} + .setup--wizard-choice--label + .setup--wizard-choice--more-info { margin-left: 0.5rem; } @@ -676,14 +699,10 @@ body { } } - #progress_content { - height: 200px; - overflow: auto; - text-align: center; - } - #installation_progress { - display: none; + #progress_content *:not(.message) + .message { + margin-top: 1.5rem; } + #fresh_content{ border: 0; min-height: 300px; diff --git a/datamodels/2.x/combodo-data-feature-removal/assets/css/DataFeatureRemoval.css b/datamodels/2.x/combodo-data-feature-removal/assets/css/DataFeatureRemoval.css new file mode 100644 index 0000000000..0005c5a7a6 --- /dev/null +++ b/datamodels/2.x/combodo-data-feature-removal/assets/css/DataFeatureRemoval.css @@ -0,0 +1,9 @@ +/* + * @copyright Copyright (C) 2010-2025 Combodo SARL + * @license http://opensource.org/licenses/AGPL-3.0 + */ + +/* + * CSS of the template page + */ + diff --git a/datamodels/2.x/combodo-data-feature-removal/assets/js/DataFeatureRemoval.js b/datamodels/2.x/combodo-data-feature-removal/assets/js/DataFeatureRemoval.js new file mode 100644 index 0000000000..42e438c5e6 --- /dev/null +++ b/datamodels/2.x/combodo-data-feature-removal/assets/js/DataFeatureRemoval.js @@ -0,0 +1,9 @@ +/* + * @copyright Copyright (C) 2010-2025 Combodo SARL + * @license http://opensource.org/licenses/AGPL-3.0 + */ + +/* + * Javascript file loaded in template page + */ + diff --git a/datamodels/2.x/combodo-data-feature-removal/composer.json b/datamodels/2.x/combodo-data-feature-removal/composer.json new file mode 100644 index 0000000000..dca5174167 --- /dev/null +++ b/datamodels/2.x/combodo-data-feature-removal/composer.json @@ -0,0 +1,16 @@ +{ + "config": { + "classmap-authoritative": true + }, + "autoload": { + "psr-4": { + "Combodo\\iTop\\DataFeatureRemoval\\": "src" + } + }, + "name": "combodo/combodo-data-feature-removal", + "type": "itop-extension", + "description": "iTop Data Feature Removal", + "require": { + "composer-runtime-api": "^2.0" + } +} \ No newline at end of file diff --git a/datamodels/2.x/combodo-data-feature-removal/composer.lock b/datamodels/2.x/combodo-data-feature-removal/composer.lock new file mode 100644 index 0000000000..7245f27055 --- /dev/null +++ b/datamodels/2.x/combodo-data-feature-removal/composer.lock @@ -0,0 +1,20 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "b862a55cbf5448fb99f0905a4db6529b", + "packages": [], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": {}, + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "composer-runtime-api": "^2.0" + }, + "platform-dev": {}, + "plugin-api-version": "2.6.0" +} diff --git a/datamodels/2.x/combodo-data-feature-removal/datamodel.combodo-data-feature-removal.xml b/datamodels/2.x/combodo-data-feature-removal/datamodel.combodo-data-feature-removal.xml new file mode 100644 index 0000000000..669a2fe273 --- /dev/null +++ b/datamodels/2.x/combodo-data-feature-removal/datamodel.combodo-data-feature-removal.xml @@ -0,0 +1,16 @@ + + + + + 30 + SystemTools + $pages/exec.php?exec_module=combodo-data-feature-removal&exec_page=index.php&c[menu]=DataFeatureRemovalMenu + 1 + + + + + 100 + + + diff --git a/datamodels/2.x/combodo-data-feature-removal/dictionaries/en.dict.combodo-data-feature-removal.php b/datamodels/2.x/combodo-data-feature-removal/dictionaries/en.dict.combodo-data-feature-removal.php new file mode 100644 index 0000000000..665af838b4 --- /dev/null +++ b/datamodels/2.x/combodo-data-feature-removal/dictionaries/en.dict.combodo-data-feature-removal.php @@ -0,0 +1,62 @@ + 'Extension management', + 'combodo-data-feature-removal/Operation:Main/Title' => 'Extension management', + + 'DataFeatureRemoval:Main:Title' => 'Extension management', + 'DataFeatureRemoval:Main:SubTitle' => 'Toggle extensions installed on your iTop', + 'DataFeatureRemoval:Failure:Title' => 'Extensions dry removal errors', + 'DataFeatureRemoval:Helper:Title' => 'Analyze if there are any data or dependency preventing you from adding/removing an extension.', + + 'DataFeatureRemoval:Features:Title' => 'Extensions', + 'DataFeatureRemoval:Result:Title' => 'Modification requested', + 'DataFeatureRemoval:Execution:Title' => 'Deletion Executions', + 'DataFeatureRemoval:Analysis:Title' => 'Analysis result', + 'DataFeatureRemoval:Analysis:Subtitle' => 'Review all elements requiring attention', + 'DataFeatureRemoval:Analysis:SubTitle' => '%1$s element(s) to clean before continuing', + + 'DataFeatureRemoval:DeletionPlan:Title' => 'Data deletion plan', + 'DataFeatureRemoval:DeletionPlan:SubTitle' => '%1$s rows to clean before continuing', + 'DataFeatureRemoval:DoDeletion:Title' => 'Do deletion', + 'DataFeatureRemoval:DoDeletion:SubTitle' => 'Remove all the entries from the database', + 'DataFeatureRemoval:DeletionPlan:Error:Issues' => 'Some objects must be deleted manually prior to cleanup', + + 'DataFeatureRemoval:Table:Analysis:ClassName' => 'Element to remove', + 'DataFeatureRemoval:Table:Analysis:FeatureName' => 'Extension name', + 'DataFeatureRemoval:Table:Analysis:Module' => 'Module name', + 'DataFeatureRemoval:Table:Analysis:Occurrence' => 'Occurrence', + + 'DataFeatureRemoval:CleanupComplete:Title' => 'All clear.', + 'DataFeatureRemoval:CompilComplete' => 'Compilation successful. No Cleanup needed. You can proceed to setup.', + + 'UI:Button:Analyze' => 'Analyze', + 'UI:Button:ModifyChoices' => 'Change my selection', + 'UI:Button:AnalyzeAndSetup' => 'Analyze and go to setup', + 'UI:Button:PlanDeletion' => 'Proceed with deletion', + 'UI:Button:DoDeletion' => 'Proceed with deletion', + 'UI:Button:BackToMain' => 'Change my selection', + 'UI:Button:Setup' => 'Run setup', + + 'UI:Action:ForceUninstall' => 'Force uninstall', + 'UI:Action:MoreInfo' => 'More information', + + 'DataFeatureRemoval:Table:Empty' => 'No data to remove', + + 'DataFeatureRemoval:Column:Class' => 'Class', + 'DataFeatureRemoval:Column:DeleteCount' => 'Entries to delete', + 'DataFeatureRemoval:Column:UpdateCount' => 'Entries to update', + 'DataFeatureRemoval:Column:IssueCount' => 'Issues found preventing automatic cleanup', + + 'DataFeatureRemoval:Column:DeletedCount' => 'Deleted entries', + 'DataFeatureRemoval:Column:UpdatedCount' => 'Updated entries', +]); diff --git a/datamodels/2.x/combodo-data-feature-removal/dictionaries/fr.dict.combodo-data-feature-removal.php b/datamodels/2.x/combodo-data-feature-removal/dictionaries/fr.dict.combodo-data-feature-removal.php new file mode 100644 index 0000000000..eba10a30da --- /dev/null +++ b/datamodels/2.x/combodo-data-feature-removal/dictionaries/fr.dict.combodo-data-feature-removal.php @@ -0,0 +1,62 @@ + 'Gestion des extensions', + 'combodo-data-feature-removal/Operation:Main/Title' => 'Gestion des extensions', + + 'DataFeatureRemoval:Main:Title' => 'Gestion des extensions', + 'DataFeatureRemoval:Main:SubTitle' => 'Sélectionner les extensions à installer sur votre iTop', + 'DataFeatureRemoval:Failure:Title' => 'Erreurs lors de la simulation de suppression d\'extensions', + 'DataFeatureRemoval:Helper:Title' => 'Activez ou désactivez les extensions installées dans votre iTop.', + + 'DataFeatureRemoval:Features:Title' => 'Extensions', + 'DataFeatureRemoval:Result:Title' => 'Modification demandée', + 'DataFeatureRemoval:Execution:Title' => 'Suppressions', + 'DataFeatureRemoval:Analysis:Title' => 'Résultat de l’analyse', + 'DataFeatureRemoval:Analysis:Subtitle' => 'Vérifier les éléments à nettoyer', + 'DataFeatureRemoval:Analysis:SubTitle' => '%1$s élément(s) à nettoyer avant de poursuivre', + + 'DataFeatureRemoval:DeletionPlan:Title' => 'Plan de suppression des données', + 'DataFeatureRemoval:DeletionPlan:SubTitle' => '%1$s ligne(s) à nettoyer avant de poursuivre', + 'DataFeatureRemoval:DoDeletion:Title' => 'Exécuter la suppression', + 'DataFeatureRemoval:DoDeletion:SubTitle' => 'Supprime toutes les entrées de la base de données', + 'DataFeatureRemoval:DeletionPlan:Error:Issues' => 'Certains objets doivent être supprimés manuellement avant le nettoyage', + + 'DataFeatureRemoval:Table:Analysis:ClassName' => 'Élément à supprimer', + 'DataFeatureRemoval:Table:Analysis:FeatureName' => 'Extension', + 'DataFeatureRemoval:Table:Analysis:Module' => 'Module', + 'DataFeatureRemoval:Table:Analysis:Occurrence' => 'Occurrence', + + 'DataFeatureRemoval:CleanupComplete:Title' => 'All clear.', + 'DataFeatureRemoval:CompilComplete' => 'Compilation successful. No Cleanup needed. You can proceed to setup.', + + 'UI:Button:Analyze' => 'Analyser', + 'UI:Button:ModifyChoices' => 'Modifier la sélection', + 'UI:Button:AnalyzeAndSetup' => 'Analyser et ouvrir l’assistant de configuration', + 'UI:Button:PlanDeletion' => 'Supprimer les données', + 'UI:Button:DoDeletion' => 'Supprimer les données', + 'UI:Button:BackToMain' => 'Modifier la sélection', + 'UI:Button:Setup' => 'Lancer le setup', + + 'UI:Action:ForceUninstall' => 'Forcer la désinstallation', + 'UI:Action:MoreInfo' => 'Plus d’informations', + + 'DataFeatureRemoval:Table:Empty' => 'Aucune donnée à supprimer', + + 'DataFeatureRemoval:Column:Class' => 'Classe', + 'DataFeatureRemoval:Column:DeleteCount' => 'Entrées à supprimer', + 'DataFeatureRemoval:Column:UpdateCount' => 'Entrées à mettre à jour', + 'DataFeatureRemoval:Column:IssueCount' => 'Problèmes empêchant le nettoyage automatique', + + 'DataFeatureRemoval:Column:DeletedCount' => 'Entrées supprimées', + 'DataFeatureRemoval:Column:UpdatedCount' => 'Entrées mises à jour', +]); diff --git a/datamodels/2.x/combodo-data-feature-removal/index.php b/datamodels/2.x/combodo-data-feature-removal/index.php new file mode 100644 index 0000000000..4dd3f0cae4 --- /dev/null +++ b/datamodels/2.x/combodo-data-feature-removal/index.php @@ -0,0 +1,20 @@ +SetDefaultOperation('Main'); +$oController->HandleOperation(); diff --git a/datamodels/2.x/combodo-data-feature-removal/model.combodo-data-feature-removal.php b/datamodels/2.x/combodo-data-feature-removal/model.combodo-data-feature-removal.php new file mode 100644 index 0000000000..e8140fa294 --- /dev/null +++ b/datamodels/2.x/combodo-data-feature-removal/model.combodo-data-feature-removal.php @@ -0,0 +1,16 @@ + 'iTop Data Feature Removal', + 'category' => 'business', + + // Setup + // + 'dependencies' => [ + + ], + 'mandatory' => true, + 'visible' => false, + + // Components + // + 'datamodel' => [ + 'vendor/autoload.php', + 'model.combodo-data-feature-removal.php', // Contains the PHP code generated by the "compilation" of datamodel.combodo-data-feature-removal.xml + ], + 'webservice' => [], + 'data.struct' => [ + // add your 'structure' definition XML files here, + ], + 'data.sample' => [ + // add your sample data XML files here, + ], + + // Documentation + // + 'doc.manual_setup' => '', // hyperlink to manual setup documentation, if any + 'doc.more_information' => '', // hyperlink to more information, if any + + // Default settings + // + 'settings' => [ + // Module specific settings go here, if any + ], + ] +); diff --git a/datamodels/2.x/combodo-data-feature-removal/src/Controller/DataFeatureRemovalController.php b/datamodels/2.x/combodo-data-feature-removal/src/Controller/DataFeatureRemovalController.php new file mode 100644 index 0000000000..94eb6ab4f2 --- /dev/null +++ b/datamodels/2.x/combodo-data-feature-removal/src/Controller/DataFeatureRemovalController.php @@ -0,0 +1,448 @@ +AddAnalyzeParams(); + $aParams['sTransactionId'] = utils::GetNewTransactionId(); + $aParams['iColumnCount'] = $this->iColumnCount; + $aParams['aAvailableExtensions'] = $this->SplitArrayIntoColumns($this->GetAvailableExtensions(), $this->iColumnCount); + $aParams['aAnalysisDataTable'] = $this->aAnalysisDataTable; + $aParams['aClasses'] = array_keys($this->aCountClassesToCleanup); + $aParams['DataFeatureRemovalErrorMessage'] = $sErrorMessage; + $aParams['bHasData'] = $this->iCount > 0; + $aParams['sSetupUrl'] = utils::GetAbsoluteUrlAppRoot().'setup'; + $aParams['iCount'] = $this->iCount; + + Session::Set('bForceCompilation', true); + $this->AddLinkedStylesheet(utils::GetAbsoluteUrlModulesRoot().DataFeatureRemovalHelper::MODULE_NAME.'/assets/css/DataFeatureRemoval.css'); + $this->AddLinkedScript(utils::GetAbsoluteUrlModulesRoot().DataFeatureRemovalHelper::MODULE_NAME.'/assets/js/DataFeatureRemoval.js'); + $this->DisplayPage($aParams); + } + + public function AddAnalyzeParams(): void + { + $aData = []; + $aColumns = []; + $this->iCount = 0; + foreach ($this->aCountClassesToCleanup as $sClass => $iCount) { + $sModuleName = MetaModel::GetModuleName($sClass); + $aExtensions = DataFeatureRemoverExtensionService::GetInstance()->GetIncludingExtensions($sModuleName); + $sExtensions = implode(' ', $aExtensions); + $aColumns = ['ClassName','FeatureName','Module','Occurrence']; + $aData[] = [$sClass,$sExtensions,$sModuleName,$iCount]; + $this->iCount += $iCount; + } + + $this->aAnalysisDataTable = $this->GetTableData('Analysis', $aColumns, $aData); + } + + public function OperationAnalysisResult(): void + { + $aParams = []; + + if (SetupUtils::IsSessionSetupTokenValid()) { + //from setup wizard/mtp + SetupUtils::EraseSetupToken(); + } else { + //from same module + $this->ValidateTransactionId(); + } + + // Display changed extensions + $aHiddenInputNames = [ + 'selected_extensions' => '[]', + 'selected_modules' => '[]', + 'display_choices' => '[]', + 'added_extensions' => '[]', + 'removed_extensions' => '[]', + 'extensions_not_uninstallable' => '[]', + 'copy_setup_files' => 1, + ]; + + $aHiddenInputs = []; + foreach ($aHiddenInputNames as $sInputName => $defaultValue) { + $aHiddenInputs[$sInputName] = utils::ReadPostedParam($sInputName, $defaultValue, utils::ENUM_SANITIZATION_FILTER_RAW_DATA); + } + $aParams['aHiddenInputs'] = $aHiddenInputs; + + $aAddedExtensions = json_decode($aHiddenInputs['added_extensions'], true); + + $aRemovedExtensions = json_decode($aHiddenInputs['removed_extensions'], true); + if ("[]" === $aHiddenInputs['selected_modules']) { + //it does not come from setup + // we get extensions from 1st screen uiblocks + $this->ReadExtensionsDiff(); + $aAddedExtensions = $this->aExtensionsToCheck['to_be_installed']; + $aHiddenInputs['added_extensions'] = $this->ConvertIntoSetupFormat($aAddedExtensions); + + $aRemovedExtensions = $this->aExtensionsToCheck['to_be_removed']; + $aHiddenInputs['removed_extensions'] = $this->ConvertIntoSetupFormat($aRemovedExtensions); + } + + $aRemoveExtensionCodes = array_keys($aRemovedExtensions); + + $aParams['aAddedExtensions'] = $aAddedExtensions; + $aParams['aRemovedExtensions'] = $aRemovedExtensions; + + DataFeatureRemovalLog::Debug(__METHOD__.' Extensions given in parameter', null, [ + 'added_extensions' => $aAddedExtensions, + 'removed_extensions' => $aRemovedExtensions]); + + $aParams['sTransactionId'] = utils::GetNewTransactionId(); + $aParams['iColumnCount'] = $this->iColumnCount; + $aParams['aAvailableExtensions'] = $this->SplitArrayIntoColumns($this->GetExtensionsDiff($aAddedExtensions, $aRemovedExtensions), $this->iColumnCount); + + $bForceCompilation = Session::Get('bForceCompilation', false); + try { + $this->Compile($aRemoveExtensionCodes, $bForceCompilation); + } catch (CoreException $e) { + $aParams['DataFeatureRemovalErrorMessage'] = $e->getHtmlDesc(); + $this->DisplayPage($aParams, 'AnalysisResult'); + return; + } catch (Exception $e) { + $aParams['DataFeatureRemovalErrorMessage'] = $e->getMessage(); + $this->DisplayPage($aParams, 'AnalysisResult'); + return; + } + + if ("[]" === $aHiddenInputs['selected_modules']) { + //to make setup redirection work, we need to pass complex data structures to setup wizards (ie extension/module lists) + $oConfig = MetaModel::GetConfig(); + $aSelectedExtensions = DataFeatureRemoverExtensionService::GetInstance()->GetExtensionMap()->GetSelectedExtensions($oConfig, $aAddedExtensions, $aRemovedExtensions); + $aHiddenInputs['selected_extensions'] = $this->ConvertIntoSetupFormat($aSelectedExtensions); + + $oRunTimeEnvironment = $this->GetRuntimeEnvironment($aRemovedExtensions); + $aSearchDirs = [$oRunTimeEnvironment->GetBuildDir()]; + $aSelectedModules = $oRunTimeEnvironment->GetModulesToLoadFromChoices($oConfig, $aSelectedExtensions, $aSearchDirs); + $aHiddenInputs['selected_modules'] = $this->ConvertIntoSetupFormat($aSelectedModules); + } + + $sSourceEnv = MetaModel::GetEnvironment(); + $oSetupAudit = new SetupAudit($sSourceEnv); + $aGetRemovedClasses = array_keys($oSetupAudit->RunDataAudit()); + DataFeatureRemovalLog::Debug(__METHOD__, null, ['aGetRemovedClasses' => $aGetRemovedClasses]); + + $aParams['aClasses'] = $aGetRemovedClasses; + + new ContextTag(ContextTag::TAG_SETUP); + $aParams['sLaunchSetupUrl'] = utils::GetAbsoluteUrlAppRoot().'setup/wizard.php'; + $aParams['aSetupParams'] = [ + "_class" => "WizStepLandingBeforeAudit", + "operation" => "next", + "_params[authent]" => SetupUtils::CreateSetupToken(), + ]; + + foreach ($aHiddenInputs as $sInputName => $sInputValue) { + $aParams['aSetupParams']["_params[$sInputName]"] = $sInputValue; + } + + [$aParams['aDeletionPlanSummary'], $aParams['iQueryCount'], $aParams['bDeletionPossible']] = $this->GetDeletionPlanSummaryTable($aGetRemovedClasses); + [$aParams['aDeletionExecutionSummary'], $aParams['bHasDeletionExecution']] = $this->GetExecutionSummaryTable(); + $aParams['bDeletionNeeded'] = ($aParams['iQueryCount'] > 0); + Session::Set('aDeletionExecutionSummary', serialize($this->aDeletionExecutionSummary)); + + $this->DisplayPage($aParams, 'AnalysisResult'); + } + + private function ConvertIntoSetupFormat(array $aData): string + { + return json_encode($aData); + } + + /** +* @param array $aRemovedExtensions +* @param bool $bForceCompilation +* @return void +* @throws \ConfigException +* @throws \CoreException + */ + private function Compile(array $aRemovedExtensions, bool $bForceCompilation = true): void + { + $sSourceEnv = MetaModel::GetEnvironment(); + $sBuildDir = APPROOT."/env-$sSourceEnv-build"; + if (! is_dir($sBuildDir)) { + SetupUtils::builddir($sBuildDir); + } + $bIsDirEmpty = count(scandir($sBuildDir)) === 2; + + if ($bIsDirEmpty || $bForceCompilation) { + DataFeatureRemovalLog::Debug( + __METHOD__, + null, + ['sSourceEnv' => $sSourceEnv, 'sBuildDir' => $sBuildDir, 'bIsDirEmpty' => $bIsDirEmpty, glob("$sBuildDir/*")] + ); + $this->GetRuntimeEnvironment($aRemovedExtensions)->CompileFrom($sSourceEnv); + } + } + + private function GetRuntimeEnvironment(array $aRemovedExtensions): RunTimeEnvironment + { + if (is_null($this->oRuntimeEnvironment)) { + $sSourceEnv = MetaModel::GetEnvironment(); + $this->oRuntimeEnvironment = new DryRemovalRuntimeEnvironment($sSourceEnv, $aRemovedExtensions); + } + + return $this->oRuntimeEnvironment; + } + + private function GetExecutionSummaryTable(): array + { + $sName = 'ExcutionSummary'; + + $aTableData = []; + if (count($this->aDeletionExecutionSummary) === 0) { + return [$aTableData, false]; + } + + $aColumns = ['Class', 'Total Deleted Count' , 'Total Updated Count', 'Deleted Count' , 'Updated Count']; + $aRows = []; + /** @var DataCleanupSummaryEntity $oSummary */ + foreach ($this->aDeletionExecutionSummary as $sClass => $oSummary) { + $aRows[] = [ + $sClass, + $oSummary->iTotalDeleteCount, + $oSummary->iTotalUpdateCount, + $oSummary->iDeleteCount, + $oSummary->iUpdateCount, + ]; + } + + $aTableData = $this->GetTableData($sName, $aColumns, $aRows); + + return [$aTableData, true]; + + } + + private function GetDeletionPlanSummaryTable(array $aRemovedClasses): array + { + $sName = 'DeletionPlanSummary'; + $oDataCleanupService = new DataCleanupService(); + $aDeletionPlanSummaryEntities = $oDataCleanupService->GetCleanupSummary($aRemovedClasses); + $aColumns = ['Class', 'Delete Count' , 'Update Count', 'Issue Count']; + $aRows = []; + $iQueryCount = 0; + $bHasIssues = false; + foreach ($aDeletionPlanSummaryEntities as $oDeletionPlanSummaryEntity) { + $aRows[] = [ + $oDeletionPlanSummaryEntity->sClass, + $oDeletionPlanSummaryEntity->iDeleteCount, + $oDeletionPlanSummaryEntity->iUpdateCount, + $oDeletionPlanSummaryEntity->iIssueCount, + ]; + $bHasIssues |= ($oDeletionPlanSummaryEntity->iIssueCount !== 0); + $iQueryCount += $oDeletionPlanSummaryEntity->iDeleteCount; + $iQueryCount += $oDeletionPlanSummaryEntity->iUpdateCount; + } + return [$this->GetTableData($sName, $aColumns, $aRows), $iQueryCount, !$bHasIssues]; + } + + public function OperationDoDeletion(): void + { + $this->ValidateTransactionId(); + + $this->aDeletionExecutionSummary = unserialize(Session::Get('aDeletionExecutionSummary')); + Session::Unset('aDeletionExecutionSummary'); + $aClasses = utils::ReadPostedParam('classes', null, utils::ENUM_SANITIZATION_FILTER_CLASS); + + $oDataCleanupService = new DataCleanupService(); + $aDeletionExecutionSummary = $oDataCleanupService->ExecuteCleanup($aClasses); + foreach ($aDeletionExecutionSummary as $sClass => $oExecutionSummary) { + if (!array_key_exists($sClass, $this->aDeletionExecutionSummary)) { + $this->aDeletionExecutionSummary[$sClass] = new DataCleanupSummaryEntity($sClass); + } + $oSummary = $this->aDeletionExecutionSummary[$sClass]; + $oSummary->iDeleteCount = $oExecutionSummary->iDeleteCount; + $oSummary->iUpdateCount = $oExecutionSummary->iUpdateCount; + $oSummary->iTotalDeleteCount += $oExecutionSummary->iDeleteCount; + $oSummary->iTotalUpdateCount += $oExecutionSummary->iUpdateCount; + } + + $this->OperationAnalysisResult(); + } + + private function GetAvailableExtensions(bool $bIncludePackageExtensions = false): array + { + $aExtensionsData = []; + if ($bIncludePackageExtensions) { + $aExtensionsRef = DataFeatureRemoverExtensionService::GetInstance()->GetExtensionMap()->GetAllExtensionsWithPreviouslyInstalled(); + } else { + $aExtensionsRef = DataFeatureRemoverExtensionService::GetInstance()->ReadItopExtensions(); + } + + foreach ($aExtensionsRef as $oExtension) { + /** @var \iTopExtension $oExtension */ + $aExtensionsData[$oExtension->sCode] = [ + 'version' => $oExtension->sVersion, + 'label' => $oExtension->sLabel, + 'code' => $oExtension->sCode, + 'description' => $oExtension->sDescription, + 'source' => $oExtension->GetExtensionSourceLabel(), + 'installed' => $oExtension->bInstalled, + 'extra_flags' => [ + 'uninstallable' => $oExtension->CanBeUninstalled(), + 'remote' => $oExtension->IsRemote(), + 'missing' => $oExtension->bRemovedFromDisk, + ], + + ]; + } + + return $aExtensionsData; + } + + private function GetExtensionsDiff(array $aAddedExtensions, array $aRemovedExtensions): array + { + $aExtensions = []; + foreach ($this->GetAvailableExtensions(true) as $sCode => $aExtension) { + $aExtension['extra_flags']['disabled'] = true; + if (isset($aAddedExtensions[$sCode])) { + $aExtension['extra_flags']['selected'] = true; + $aExtensions[$sCode] = $aExtension; + } elseif (isset($aRemovedExtensions[$sCode])) { + $aExtension['extra_flags']['selected'] = false; + $aExtensions[$sCode] = $aExtension; + } + } + + return $aExtensions; + } + + private function GetTableData(string $sTableName, array $aColumns, array $aData): array + { + if (empty($aData)) { + return [ + 'Type' => 'Table', + 'Columns' => [['label' => '']], + 'Data' => [[ Dict::S('DataFeatureRemoval:Table:Empty')]], + ]; + } + + $aNewColumns = []; + foreach ($aColumns as $sColumn) { + $aNewColumns[] = ['label' => Dict::S("DataFeatureRemoval:Table:$sTableName:$sColumn", Dict::S("DataFeatureRemoval:Column:$sColumn", $sColumn))]; + } + $aColumns = $aNewColumns; + + return [ + 'Type' => 'Table', + 'Columns' => $aColumns, + 'Data' => $aData, + ]; + } + + /** + * @return void + * @throws \Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalException + */ + private function ValidateTransactionId(): void + { + if (empty($_POST)) { + return; + } + + $sTransactionId = utils::ReadPostedParam('transaction_id', null, utils::ENUM_SANITIZATION_FILTER_TRANSACTION_ID); + DataFeatureRemovalLog::Debug(__FUNCTION__.": Transaction [$sTransactionId]"); + if (empty($sTransactionId) || !utils::IsTransactionValid($sTransactionId, false)) { + throw new DataFeatureRemovalException(Dict::S("iTopUpdate:Error:InvalidToken")); + } + } + + /** + * Read extensions selected from posted parameters + * @return int Number of extensions to be added or removed + */ + public function ReadExtensionsDiff(): int + { + if (!is_null($this->aExtensionsToCheck)) { + return count($this->aExtensionsToCheck['to_be_installed']) + count($this->aExtensionsToCheck['to_be_removed']); + } + + $aAvailableExtensions = $this->GetAvailableExtensions(); + $aSelectedExtensionsFromUI = utils::ReadPostedParam('aSelectedExtensions', []); + $this->aExtensionsToCheck = [ + 'to_be_installed' => [], + 'to_be_removed' => [], + ]; + foreach ($aAvailableExtensions as $sCode => &$aExtensionData) { + if (!isset($aSelectedExtensionsFromUI[$sCode])) { + continue; + } + + if ($aExtensionData['installed'] && $aSelectedExtensionsFromUI[$sCode] !== 'on') { + $aExtensionData['extra_flags']['selected'] = false; + $sLabel = $aAvailableExtensions[$sCode]['label']; + $this->aExtensionsToCheck['to_be_removed'][$sCode] = $sLabel; + if (!$aExtensionData['extra_flags']['uninstallable'] || $aExtensionData['extra_flags']['remote']) { + $this->bForcedUninstallation = true; + } + } elseif (!$aExtensionData['installed'] && $aSelectedExtensionsFromUI[$sCode] === 'on') { + $aExtensionData['extra_flags']['selected'] = true; + $sLabel = $aAvailableExtensions[$sCode]['label']; + $this->aExtensionsToCheck['to_be_installed'][$sCode] = $sLabel; + } + } + return count($this->aExtensionsToCheck['to_be_installed']) + count($this->aExtensionsToCheck['to_be_removed']); + } + + /** + * Divide an array into several sub arrays, distributing elements so that every sub array has an equal amount of elements + * @param mixed[] $aInput + * @param int $iColNumber + * + * @return array[] + */ + private function SplitArrayIntoColumns(array $aInput, int $iColNumber) + { + $aOutput = array_fill(0, $iColNumber, []); + $iIndex = 0; + foreach ($aInput as $mItem) { + //Split extensions in $iColNumber columns + $aOutput[$iIndex % $this->iColumnCount][] = $mItem; + $iIndex++; + } + return $aOutput; + } +} diff --git a/datamodels/2.x/combodo-data-feature-removal/src/Entity/DataCleanupSummaryEntity.php b/datamodels/2.x/combodo-data-feature-removal/src/Entity/DataCleanupSummaryEntity.php new file mode 100644 index 0000000000..c227fdeea9 --- /dev/null +++ b/datamodels/2.x/combodo-data-feature-removal/src/Entity/DataCleanupSummaryEntity.php @@ -0,0 +1,21 @@ +sClass = $sClass; + } +} diff --git a/datamodels/2.x/combodo-data-feature-removal/src/Helper/DataFeatureRemovalConfig.php b/datamodels/2.x/combodo-data-feature-removal/src/Helper/DataFeatureRemovalConfig.php new file mode 100644 index 0000000000..bb07f28ad8 --- /dev/null +++ b/datamodels/2.x/combodo-data-feature-removal/src/Helper/DataFeatureRemovalConfig.php @@ -0,0 +1,52 @@ +Get($sParamName, $default); + + return boolval($res); + } + + public function IsEnabled(): bool + { + return $this->GetBoolean('enable', false); + } + + public function Set(string $sParamName, $value) + { + $oConfig = utils::GetConfig(); + $oConfig->SetModuleSetting(DataFeatureRemovalHelper::MODULE_NAME, $sParamName, $value); + } +} diff --git a/datamodels/2.x/combodo-data-feature-removal/src/Helper/DataFeatureRemovalException.php b/datamodels/2.x/combodo-data-feature-removal/src/Helper/DataFeatureRemovalException.php new file mode 100644 index 0000000000..8c1c707488 --- /dev/null +++ b/datamodels/2.x/combodo-data-feature-removal/src/Helper/DataFeatureRemovalException.php @@ -0,0 +1,30 @@ +getTraceAsString(); + $sError = $previous->getMessage(); + } else { + $sStack = $this->getTraceAsString(); + $sError = ''; + } + + $aContext['error'] = $sError; + $aContext['stack'] = $sStack; + DataFeatureRemovalLog::Error($message, null, $aContext); + parent::__construct($message, $code, $previous); + } +} diff --git a/datamodels/2.x/combodo-data-feature-removal/src/Helper/DataFeatureRemovalHelper.php b/datamodels/2.x/combodo-data-feature-removal/src/Helper/DataFeatureRemovalHelper.php new file mode 100644 index 0000000000..2a4a33d397 --- /dev/null +++ b/datamodels/2.x/combodo-data-feature-removal/src/Helper/DataFeatureRemovalHelper.php @@ -0,0 +1,13 @@ +oExecutionLimits = new ExecutionLimits($iMaxExecutionTime, $iMaxMemoryPercent); + } + + /** + * Get a summary of the deletion plan computed for the classes. + * The result is used for display + * + * @param array|null $aClasses + * + * @return array<\Combodo\iTop\DataFeatureRemoval\Entity\DataCleanupSummaryEntity> + * @throws \CoreException + * @throws \CoreUnexpectedValue + * @throws \MySQLException + * @throws \Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalException + */ + public function GetCleanupSummary(?array $aClasses): array + { + return $this->ExecuteCleanup($aClasses ?? [], oObjectService: new ObjectServiceSummary()); + } + + private function GetNextObjectToDelete(array $aClasses): ?DBObject + { + foreach ($aClasses as $sClass) { + $oFilter = new DBObjectSearch($sClass); + $oFilter->AllowAllData(); + $oSet = new \DBObjectSet($oFilter); + while ($oObject = $oSet->Fetch()) { + if (!$this->IsVisited($oObject)) { + return $oObject; + } + } + } + + return null; + } + + /** + * @param array $aClasses + * @param \Combodo\iTop\DataFeatureRemoval\Service\iObjectService|null $oObjectService + * + * @return array execution summary + * @throws \ArchivedObjectException + * @throws \Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalException + * @throws \CoreException + * @throws \CoreUnexpectedValue + * @throws \MySQLException + */ + public function ExecuteCleanup(array $aClasses, ?iObjectService $oObjectService = null): array + { + $this->oObjectService = $oObjectService ?? new ObjectService(); + + $this->aVisited = []; + + while ($oObject = $this->GetNextObjectToDelete($aClasses)) { + if ($this->RecursiveDeletion($oObject) === false) { + // Timeout, stop here + break; + } + } + return $this->oObjectService->GetSummary(); + + } + + private function MarkObjectAsVisited(DBObject $oObject): void + { + $sClass = get_class($oObject); + $sId = $oObject->GetKey(); + $sKey = "$sClass-$sId"; + $this->aVisited[$sKey] = true; + } + + private function IsVisited(DBObject $oObject): bool + { + $sClass = get_class($oObject); + $sId = $oObject->GetKey(); + $sKey = "$sClass-$sId"; + + $bRes = $this->aVisited[$sKey] ?? false; + DataFeatureRemovalLog::Debug('Checking if object is visited', null, [$sKey, $bRes]); + return $bRes; + } + + /** + * + * @param \DBObject $oObjectToClean + * + * @return bool true if deletion is complete, false in case of timeout or memory limit reached + * + * @throws \ArchivedObjectException + * @throws \Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalException + * @throws \CoreException + * @throws \CoreUnexpectedValue + * @throws \MySQLException + */ + private function RecursiveDeletion(DBObject $oObjectToClean): bool + { + $this->MarkObjectAsVisited($oObjectToClean); + $sClass = get_class($oObjectToClean); + + $aReferencingMe = MetaModel::EnumReferencingClasses($sClass); + foreach ($aReferencingMe as $sRemoteClass => $aExtKeys) { + /** @var \AttributeExternalKey $oExtKeyAttDef */ + foreach ($aExtKeys as $sExtKeyAttCode => $oExtKeyAttDef) { + // skip if this external key is behind an external field + if (!$oExtKeyAttDef->IsExternalKey(EXTKEY_ABSOLUTE)) { + continue; + } + + $oSearch = new DBObjectSearch($sRemoteClass); + $oSearch->AddCondition($sExtKeyAttCode, $oObjectToClean->GetKey(), '='); + $oSearch->AllowAllData(); + $oSet = new CMDBObjectSet($oSearch); + $oSet->OptimizeColumnLoad([$sRemoteClass => [$oExtKeyAttDef->GetCode()]]); + /** @var DBObject $oDependentObj */ + while ($oDependentObj = $oSet->Fetch()) { + $iDeletePropagationOption = $oExtKeyAttDef->GetDeletionPropagationOption(); + if ($iDeletePropagationOption == DEL_MANUAL) { + $this->oObjectService->SetIssue(get_class($oDependentObj)); + continue; + } + + if ($oExtKeyAttDef->IsNullAllowed()) { + // Optional external key, list to reset + if (($iDeletePropagationOption == DEL_MOVEUP) && ($oExtKeyAttDef->IsHierarchicalKey())) { + // Move the child up one level i.e. set the same parent as the current object + $iParentId = $oObjectToClean->Get($oExtKeyAttDef->GetCode()); + $this->oObjectService->Update($oDependentObj, $oExtKeyAttDef->GetCode(), $iParentId); + } else { + $this->oObjectService->Update($oDependentObj, $oExtKeyAttDef->GetCode(), 0); + } + if ($this->oExecutionLimits->ShouldStopExecution()) { + return false; + } + } else { + // Propagate deletion only if not visited + if ($this->IsVisited($oDependentObj)) { + continue; + } + if (!$this->RecursiveDeletion($oDependentObj)) { + // Timeout + return false; + } + } + + } + } + } + + $this->oObjectService->Delete($sClass, $oObjectToClean->GetKey()); + + if ($this->oExecutionLimits->ShouldStopExecution()) { + return false; + } + + return true; + } +} diff --git a/datamodels/2.x/combodo-data-feature-removal/src/Service/DataFeatureRemoverExtensionService.php b/datamodels/2.x/combodo-data-feature-removal/src/Service/DataFeatureRemoverExtensionService.php new file mode 100644 index 0000000000..e25c5a755a --- /dev/null +++ b/datamodels/2.x/combodo-data-feature-removal/src/Service/DataFeatureRemoverExtensionService.php @@ -0,0 +1,90 @@ +aIncludingExtensionsByModuleName) === 0) { + foreach ($this->ReadItopExtensions() as $oExtension) { + $aModuleNames = $oExtension->aModules; + if (is_array($aModuleNames) && count($aModuleNames) > 0) { + foreach ($aModuleNames as $sModule) { + $aExtensions = $this->aIncludingExtensionsByModuleName[$sModule] ?? []; + $aExtensions[] = $oExtension->sLabel.'/'.$oExtension->sVersion; + $this->aIncludingExtensionsByModuleName[$sModule] = $aExtensions; + } + } + } + } + + return $this->aIncludingExtensionsByModuleName[$sModuleName] ?? []; + } + + /** + * @return \iTopExtensionsMap + */ + public function GetExtensionMap(): iTopExtensionsMap + { + if (is_null($this->oMap)) { + $this->oMap = new iTopExtensionsMap(); + $this->oMap->LoadInstalledExtensionsFromDatabase(MetaModel::GetConfig()); + } + return $this->oMap; + } + + /** + * @return iTopExtension[] + */ + public function ReadItopExtensions(): array + { + if (count($this->aItopExtensions) === 0) { + $this->aItopExtensions = $this->GetExtensionMap()->GetAllExtensionsToDisplayInSetup(true); + + uasort($this->aItopExtensions, function (iTopExtension $oiTopExtension1, iTopExtension $oiTopExtension2) { + return strcmp($oiTopExtension1->sLabel, $oiTopExtension2->sLabel); + }); + } + + return $this->aItopExtensions; + } +} diff --git a/datamodels/2.x/combodo-data-feature-removal/src/Service/ObjectService.php b/datamodels/2.x/combodo-data-feature-removal/src/Service/ObjectService.php new file mode 100644 index 0000000000..e0c94b75a0 --- /dev/null +++ b/datamodels/2.x/combodo-data-feature-removal/src/Service/ObjectService.php @@ -0,0 +1,60 @@ +Set($sAttCode, $value); + $oToUpdate->DBUpdate(); + parent::Update($oToUpdate, $sAttCode, $value); + } + + public function Delete(string $sClass, string $sId): void + { + try { + CMDBSource::Query('START TRANSACTION'); + // Delete any existing change tracking about the current object + $oFilter = new DBObjectSearch('CMDBChangeOp'); + $oFilter->AddCondition('objclass', $sClass, '='); + $oFilter->AddCondition('objkey', $sId, '='); + MetaModel::PurgeData($oFilter); + + // Delete the entry + $aClassesToRemove = array_merge(MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL), MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_EXCLUDELEAF, false)); + foreach ($aClassesToRemove as $sParentClass) { + /** @var DBObjectSearch $oFilter */ + $oFilter = DBObjectSearch::FromOQL_AllData("SELECT $sParentClass WHERE id=:id"); + $sQuery = $oFilter->MakeDeleteQuery(['id' => $sId]); + CMDBSource::DeleteFrom($sQuery); + } + + CMDBSource::Query('COMMIT'); + parent::Delete($sClass, $sId); + + } catch (\Exception $e) { + DataFeatureRemovalLog::Exception(__METHOD__.': Cleanup failed', $e); + CMDBSource::Query('ROLLBACK'); + throw $e; + } + } + + public function SetIssue(string $sClass): void + { + throw new DataFeatureRemovalException('Deletion Plan cannot be executed due to issues'); + } + +} diff --git a/datamodels/2.x/combodo-data-feature-removal/src/Service/ObjectServiceSummary.php b/datamodels/2.x/combodo-data-feature-removal/src/Service/ObjectServiceSummary.php new file mode 100644 index 0000000000..6e209b78c1 --- /dev/null +++ b/datamodels/2.x/combodo-data-feature-removal/src/Service/ObjectServiceSummary.php @@ -0,0 +1,71 @@ + DeletionPlanSummaryEntity] + */ +class ObjectServiceSummary implements iObjectService +{ + private array $aSummary = []; + + public function Update(DBObject $oToUpdate, string $sAttCode, $value): void + { + $sClass = get_class($oToUpdate); + DataFeatureRemovalLog::Debug('Object to update', null, ['class' => $sClass, 'id' => $oToUpdate->GetKey(), 'code' => $sAttCode, 'value' => "$value"]); + if (! array_key_exists($sClass, $this->aSummary)) { + $this->aSummary[$sClass] = new DataCleanupSummaryEntity($sClass); + } + $oDeletionPlanSummaryEntity = $this->aSummary[$sClass]; + $oDeletionPlanSummaryEntity->iUpdateCount++; + $oDeletionPlanSummaryEntity->iTotalUpdateCount++; + } + + public function Delete(string $sClass, string $sId): void + { + DataFeatureRemovalLog::Debug('Object to delete', null, ['class' => $sClass, 'id' => $sId]); + if (!array_key_exists($sClass, $this->aSummary)) { + $this->aSummary[$sClass] = new DataCleanupSummaryEntity($sClass); + } + $oDeletionPlanSummaryEntity = $this->aSummary[$sClass]; + $oDeletionPlanSummaryEntity->iDeleteCount++; + $oDeletionPlanSummaryEntity->iTotalDeleteCount++; + } + + public function SetIssue(string $sClass): void + { + DataFeatureRemovalLog::Debug('Issue on object', null, ['class' => $sClass]); + if (!array_key_exists($sClass, $this->aSummary)) { + $this->aSummary[$sClass] = new DataCleanupSummaryEntity($sClass); + } + $oDeletionPlanSummaryEntity = $this->aSummary[$sClass]; + $oDeletionPlanSummaryEntity->iIssueCount++; + } + + public function GetSummary(): array + { + return $this->aSummary; + } + + public function SetSummary(array $aSummary): void + { + foreach ($aSummary as $sClass => $oPreviousSummaryEntity) { + $oSummaryEntity = new DataCleanupSummaryEntity($sClass); + $oSummaryEntity->iTotalUpdateCount = $oPreviousSummaryEntity->iTotalUpdateCount; + $oSummaryEntity->iTotalDeleteCount = $oPreviousSummaryEntity->iTotalDeleteCount; + + $this->aSummary[$sClass] = $oSummaryEntity; + } + } +} diff --git a/datamodels/2.x/combodo-data-feature-removal/src/Service/iObjectService.php b/datamodels/2.x/combodo-data-feature-removal/src/Service/iObjectService.php new file mode 100644 index 0000000000..f12831b74e --- /dev/null +++ b/datamodels/2.x/combodo-data-feature-removal/src/Service/iObjectService.php @@ -0,0 +1,21 @@ + + {% UIAlert ForFailure { sTitle:'DataFeatureRemoval:Failure:Title'|dict_s, sId: 'feature_removal_error_msg', sContent:DataFeatureRemovalErrorMessage } %} + {% EndUIAlert %} + + + {% UIPanel Neutral { sTitle:'DataFeatureRemoval:Result:Title'|dict_s, sSubTitle: '' } %} + {% UIMultiColumn Standard {} %} + {% for iColumnIndex in 0..iColumnCount-1 %} + {% UIColumn Standard {} %} + {% for aExtension in aAvailableExtensions[iColumnIndex] %} + {% if aExtension['installed'] %} + {% UIExtensionDetails Installed { sCode : aExtension['code'], sLabel : aExtension['label'], sDescription : aExtension['description'], aMetaData : [aExtension['version'], aExtension['source']], aExtraFlags : aExtension['extra_flags']} %}{% EndUIExtensionDetails %} + {% else %} + {% UIExtensionDetails NotInstalled { sCode : aExtension['code'], sLabel : aExtension['label'], sDescription : aExtension['description'], aMetaData : [aExtension['version'], aExtension['source']], aExtraFlags : aExtension['extra_flags']} %}{% EndUIExtensionDetails %} + {% endif %} + {% endfor %} + {% EndUIColumn %} + {% endfor %} + {% EndUIMultiColumn %} + {% EndUIPanel %} + {% else %} + {% UIPanel Neutral { sTitle:'DataFeatureRemoval:Result:Title'|dict_s, sSubTitle: '' } %} + {% UIMultiColumn Standard {} %} + {% for iColumnIndex in 0..iColumnCount-1 %} + {% UIColumn Standard {} %} + {% for aExtension in aAvailableExtensions[iColumnIndex] %} + {% if aExtension['installed'] %} + {% UIExtensionDetails Installed { sCode : aExtension['code'], sLabel : aExtension['label'], sDescription : aExtension['description'], aMetaData : [aExtension['version'], aExtension['source']], aExtraFlags : aExtension['extra_flags']} %}{% EndUIExtensionDetails %} + {% else %} + {% UIExtensionDetails NotInstalled { sCode : aExtension['code'], sLabel : aExtension['label'], sDescription : aExtension['description'], aMetaData : [aExtension['version'], aExtension['source']], aExtraFlags : aExtension['extra_flags']} %}{% EndUIExtensionDetails %} + {% endif %} + {% endfor %} + {% EndUIColumn %} + {% endfor %} + {% EndUIMultiColumn %} + {% EndUIPanel %} + + {% if bDeletionNeeded %} + {% UIFieldSet Standard {sLegend:'DataFeatureRemoval:DeletionPlan:Title'|dict_s} %} + {% UIDataTable ForForm { sRef:'aDeletionPlanSummary', aColumns:aDeletionPlanSummary.Columns, aData:aDeletionPlanSummary.Data} %}{% EndUIDataTable %} + {% EndUIFieldSet %} + {% if bDeletionPossible %} + {% UIForm Standard {} %} + {% UIInput ForHidden { sName:'transaction_id', sValue:sTransactionId} %} + {% UIInput ForHidden { sName:'operation', sValue:'DoDeletion'} %} + {% for sKey, sClass in aClasses %} + {% UIInput ForHidden { sName:"classes[" ~ sKey ~ "]", sValue:sClass } %} + {% endfor %} + {% for sCode, sLabel in aAddedExtensions %} + {% UIInput ForHidden { sName:"aAddedExtensions[" ~ sCode ~ "]", sValue:sLabel } %} + {% endfor %} + {% for sCode, sLabel in aRemovedExtensions %} + {% UIInput ForHidden { sName:"aRemovedExtensions[" ~ sCode ~ "]", sValue:sLabel } %} + {% endfor %} + {% for sInputName, sValue in aHiddenInputs %} + {% UIInput ForHidden { sName:sInputName, sValue:sValue } %} + {% endfor %} + {% UIToolbar ForButton {} %} + {% UIButton ForPrimaryAction {sLabel:'UI:Button:DoDeletion'|dict_s, sName:'btn_deletion', sId:'btn_deletion', bIsSubmit:true} %} + {% EndUIToolbar %} + {% EndUIForm %} + {% else %} + {% UIAlert ForFailure { sContent: 'DataFeatureRemoval:DeletionPlan:Error:Issues'|dict_s } %}{% EndUIAlert %} + {% endif %} + {% else %} + {% UIAlert ForSuccess { sTitle:'DataFeatureRemoval:CleanupComplete:Title'|dict_s, sContent:'DataFeatureRemoval:CompilComplete'|dict_s, sId:value } %}{% EndUIAlert %} + + {% UIForm Standard {'sId':'launch-setup-form', Action:sLaunchSetupUrl, 'EncType': 'application/x-www-form-urlencoded'} %} + {% for sKey, sValue in aSetupParams %} + {% UIInput ForHidden { sName:sKey, sValue:sValue } %} + {% endfor %} + {% UIButton ForPrimaryAction {sLabel:'UI:Button:Setup'|dict_s, sName:'btn_setup', sId:'btn_setup', bIsSubmit:true} %} + {% EndUIForm %} + {% endif %} + + {% if bHasDeletionExecution %} + {% UIFieldSet Standard {sLegend:'DataFeatureRemoval:Execution:Title'|dict_s} %} + {% UIDataTable ForForm { sRef:'aDeletionExecutionSummary', aColumns:aDeletionExecutionSummary.Columns, aData:aDeletionExecutionSummary.Data} %}{% EndUIDataTable %} + {% EndUIFieldSet %} + {% endif %} + {% endif %} + + {% UIForm Standard {} %} + {% UIInput ForHidden { sName:'transaction_id', sValue:sTransactionId} %} + {% UIInput ForHidden { sName:'operation', sValue:'Main'} %} + {% UIToolbar ForButton {} %} + {% UIButton ForPrimaryAction {sLabel:'UI:Button:BackToMain'|dict_s, sName:'btn_back', sId:'btn_back', bIsSubmit:true} %} + {% EndUIToolbar %} + {% EndUIForm %} +{% EndUIPanel %} diff --git a/datamodels/2.x/combodo-data-feature-removal/templates/DoDeletion.html.twig b/datamodels/2.x/combodo-data-feature-removal/templates/DoDeletion.html.twig new file mode 100644 index 0000000000..3deadb13b2 --- /dev/null +++ b/datamodels/2.x/combodo-data-feature-removal/templates/DoDeletion.html.twig @@ -0,0 +1,14 @@ +{# @copyright Copyright (C) 2010-2026 Combodo SARL #} +{# @license http://opensource.org/licenses/AGPL-3.0 #} + +{% UIPanel ForInformation { sTitle:'DataFeatureRemoval:DoDeletion:Title'|dict_s, sSubTitle: 'DataFeatureRemoval:DoDeletion:SubTitle'|dict_s } %} + {% UIDataTable ForForm { sRef:'aDeletionExecutionSummary', aColumns:aDeletionExecutionSummary.Columns, aData:aDeletionExecutionSummary.Data} %}{% EndUIDataTable %} +{% EndUIPanel %} + +{% UIForm Standard {} %} + {% UIInput ForHidden { sName:'transaction_id', sValue:sTransactionId} %} + {% UIInput ForHidden { sName:'operation', sValue:'Main'} %} + {% UIToolbar ForButton {} %} + {% UIButton ForPrimaryAction {sLabel:'UI:Button:BackToMain'|dict_s, sName:'btn_back_to_main', sId:'btn_back_to_main', bIsSubmit:true} %} + {% EndUIToolbar %} +{% EndUIForm %} \ No newline at end of file diff --git a/datamodels/2.x/combodo-data-feature-removal/templates/Features.html.twig b/datamodels/2.x/combodo-data-feature-removal/templates/Features.html.twig new file mode 100644 index 0000000000..a2c2c84f18 --- /dev/null +++ b/datamodels/2.x/combodo-data-feature-removal/templates/Features.html.twig @@ -0,0 +1,28 @@ +{# @copyright Copyright (C) 2010-2024 Combodo SAS #} +{# @license http://opensource.org/licenses/AGPL-3.0 #} + + +{% UIForm Standard {} %} + {% UIInput ForHidden {sName:'operation', sValue:'AnalysisResult'} %} + {% UIInput ForHidden {sName:'transaction_id', sValue:sTransactionId} %} + + {% UIPanel Neutral { sTitle:'DataFeatureRemoval:Features:Title'|dict_s, sSubTitle: '' } %} + {% UIMultiColumn Standard {} %} + {% for iColumnIndex in 0..iColumnCount-1 %} + {% UIColumn Standard {} %} + {% for aExtension in aAvailableExtensions[iColumnIndex] %} + {% if aExtension['installed'] %} + {% UIExtensionDetails Installed { sCode : aExtension['code'], sLabel : aExtension['label'], sDescription : aExtension['description'], aMetaData : [aExtension['version'], aExtension['source']], aExtraFlags : aExtension['extra_flags']} %}{% EndUIExtensionDetails %} + {% else %} + {% UIExtensionDetails NotInstalled { sCode : aExtension['code'], sLabel : aExtension['label'], sDescription : aExtension['description'], aMetaData : [aExtension['version'], aExtension['source']], aExtraFlags : aExtension['extra_flags']} %}{% EndUIExtensionDetails %} + {% endif %} + {% endfor %} + {% EndUIColumn %} + {% endfor %} + {% EndUIMultiColumn %} + {% EndUIPanel %} + + {% UIToolbar ForButton {} %} + {% UIButton ForPrimaryAction {sLabel:'UI:Button:Analyze'|dict_s, sName:'btn_apply', sId:'btn_apply', bIsSubmit:true} %} + {% EndUIToolbar %} +{% EndUIForm %} diff --git a/datamodels/2.x/combodo-data-feature-removal/templates/Main.html.twig b/datamodels/2.x/combodo-data-feature-removal/templates/Main.html.twig new file mode 100644 index 0000000000..7d71bf00eb --- /dev/null +++ b/datamodels/2.x/combodo-data-feature-removal/templates/Main.html.twig @@ -0,0 +1,17 @@ +{# @copyright Copyright (C) 2010-2025 Combodo SARL #} +{# @license http://opensource.org/licenses/AGPL-3.0 #} + +{# Usable variables: #} +{# * sTitle => page title #} +{# * sMessage => success message #} +{# * sError => error message #} + +{# DataFeatureRemoval #} + +{% UIPanel ForInformation { sTitle:'DataFeatureRemoval:Main:Title'|dict_s, sSubTitle: 'DataFeatureRemoval:Main:SubTitle'|dict_s } %} + + {% UIAlert ForInformation { sTitle:'DataFeatureRemoval:Helper:Title'|dict_s } %} + {% EndUIAlert %} + + {% include 'Features.html.twig' %} +{% EndUIPanel %} diff --git a/datamodels/2.x/combodo-data-feature-removal/vendor/autoload.php b/datamodels/2.x/combodo-data-feature-removal/vendor/autoload.php new file mode 100644 index 0000000000..a18424e39d --- /dev/null +++ b/datamodels/2.x/combodo-data-feature-removal/vendor/autoload.php @@ -0,0 +1,22 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + * @see https://www.php-fig.org/psr/psr-0/ + * @see https://www.php-fig.org/psr/psr-4/ + */ +class ClassLoader +{ + /** @var \Closure(string):void */ + private static $includeFile; + + /** @var string|null */ + private $vendorDir; + + // PSR-4 + /** + * @var array> + */ + private $prefixLengthsPsr4 = array(); + /** + * @var array> + */ + private $prefixDirsPsr4 = array(); + /** + * @var list + */ + private $fallbackDirsPsr4 = array(); + + // PSR-0 + /** + * List of PSR-0 prefixes + * + * Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2'))) + * + * @var array>> + */ + private $prefixesPsr0 = array(); + /** + * @var list + */ + private $fallbackDirsPsr0 = array(); + + /** @var bool */ + private $useIncludePath = false; + + /** + * @var array + */ + private $classMap = array(); + + /** @var bool */ + private $classMapAuthoritative = false; + + /** + * @var array + */ + private $missingClasses = array(); + + /** @var string|null */ + private $apcuPrefix; + + /** + * @var array + */ + private static $registeredLoaders = array(); + + /** + * @param string|null $vendorDir + */ + public function __construct($vendorDir = null) + { + $this->vendorDir = $vendorDir; + self::initializeIncludeClosure(); + } + + /** + * @return array> + */ + public function getPrefixes() + { + if (!empty($this->prefixesPsr0)) { + return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); + } + + return array(); + } + + /** + * @return array> + */ + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + /** + * @return list + */ + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + /** + * @return list + */ + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + /** + * @return array Array of classname => path + */ + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param array $classMap Class to filename map + * + * @return void + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param list|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + * + * @return void + */ + public function add($prefix, $paths, $prepend = false) + { + $paths = (array) $paths; + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param list|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories + * + * @throws \InvalidArgumentException + * + * @return void + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + $paths = (array) $paths; + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param list|string $paths The PSR-0 base directories + * + * @return void + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param list|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + * + * @return void + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + * + * @return void + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + * + * @return void + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * APCu prefix to use to cache found/not-found classes, if the extension is enabled. + * + * @param string|null $apcuPrefix + * + * @return void + */ + public function setApcuPrefix($apcuPrefix) + { + $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; + } + + /** + * The APCu prefix in use, or null if APCu caching is not enabled. + * + * @return string|null + */ + public function getApcuPrefix() + { + return $this->apcuPrefix; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + * + * @return void + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + + if (null === $this->vendorDir) { + return; + } + + if ($prepend) { + self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; + } else { + unset(self::$registeredLoaders[$this->vendorDir]); + self::$registeredLoaders[$this->vendorDir] = $this; + } + } + + /** + * Unregisters this instance as an autoloader. + * + * @return void + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + + if (null !== $this->vendorDir) { + unset(self::$registeredLoaders[$this->vendorDir]); + } + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return true|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + $includeFile = self::$includeFile; + $includeFile($file); + + return true; + } + + return null; + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + return false; + } + if (null !== $this->apcuPrefix) { + $file = apcu_fetch($this->apcuPrefix.$class, $hit); + if ($hit) { + return $file; + } + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if (false === $file && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if (null !== $this->apcuPrefix) { + apcu_add($this->apcuPrefix.$class, $file); + } + + if (false === $file) { + // Remember that this class does not exist. + $this->missingClasses[$class] = true; + } + + return $file; + } + + /** + * Returns the currently registered loaders keyed by their corresponding vendor directories. + * + * @return array + */ + public static function getRegisteredLoaders() + { + return self::$registeredLoaders; + } + + /** + * @param string $class + * @param string $ext + * @return string|false + */ + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + $subPath = $class; + while (false !== $lastPos = strrpos($subPath, '\\')) { + $subPath = substr($subPath, 0, $lastPos); + $search = $subPath . '\\'; + if (isset($this->prefixDirsPsr4[$search])) { + $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); + foreach ($this->prefixDirsPsr4[$search] as $dir) { + if (file_exists($file = $dir . $pathEnd)) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + + return false; + } + + /** + * @return void + */ + private static function initializeIncludeClosure() + { + if (self::$includeFile !== null) { + return; + } + + /** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + * + * @param string $file + * @return void + */ + self::$includeFile = \Closure::bind(static function($file) { + include $file; + }, null, null); + } +} diff --git a/datamodels/2.x/combodo-data-feature-removal/vendor/composer/InstalledVersions.php b/datamodels/2.x/combodo-data-feature-removal/vendor/composer/InstalledVersions.php new file mode 100644 index 0000000000..2052022fd8 --- /dev/null +++ b/datamodels/2.x/combodo-data-feature-removal/vendor/composer/InstalledVersions.php @@ -0,0 +1,396 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer; + +use Composer\Autoload\ClassLoader; +use Composer\Semver\VersionParser; + +/** + * This class is copied in every Composer installed project and available to all + * + * See also https://getcomposer.org/doc/07-runtime.md#installed-versions + * + * To require its presence, you can require `composer-runtime-api ^2.0` + * + * @final + */ +class InstalledVersions +{ + /** + * @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to + * @internal + */ + private static $selfDir = null; + + /** + * @var mixed[]|null + * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array}|array{}|null + */ + private static $installed; + + /** + * @var bool + */ + private static $installedIsLocalDir; + + /** + * @var bool|null + */ + private static $canGetVendors; + + /** + * @var array[] + * @psalm-var array}> + */ + private static $installedByVendor = array(); + + /** + * Returns a list of all package names which are present, either by being installed, replaced or provided + * + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackages() + { + $packages = array(); + foreach (self::getInstalled() as $installed) { + $packages[] = array_keys($installed['versions']); + } + + if (1 === \count($packages)) { + return $packages[0]; + } + + return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); + } + + /** + * Returns a list of all package names with a specific type e.g. 'library' + * + * @param string $type + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackagesByType($type) + { + $packagesByType = array(); + + foreach (self::getInstalled() as $installed) { + foreach ($installed['versions'] as $name => $package) { + if (isset($package['type']) && $package['type'] === $type) { + $packagesByType[] = $name; + } + } + } + + return $packagesByType; + } + + /** + * Checks whether the given package is installed + * + * This also returns true if the package name is provided or replaced by another package + * + * @param string $packageName + * @param bool $includeDevRequirements + * @return bool + */ + public static function isInstalled($packageName, $includeDevRequirements = true) + { + foreach (self::getInstalled() as $installed) { + if (isset($installed['versions'][$packageName])) { + return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false; + } + } + + return false; + } + + /** + * Checks whether the given package satisfies a version constraint + * + * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call: + * + * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3') + * + * @param VersionParser $parser Install composer/semver to have access to this class and functionality + * @param string $packageName + * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package + * @return bool + */ + public static function satisfies(VersionParser $parser, $packageName, $constraint) + { + $constraint = $parser->parseConstraints((string) $constraint); + $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); + + return $provided->matches($constraint); + } + + /** + * Returns a version constraint representing all the range(s) which are installed for a given package + * + * It is easier to use this via isInstalled() with the $constraint argument if you need to check + * whether a given version of a package is installed, and not just whether it exists + * + * @param string $packageName + * @return string Version constraint usable with composer/semver + */ + public static function getVersionRanges($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + $ranges = array(); + if (isset($installed['versions'][$packageName]['pretty_version'])) { + $ranges[] = $installed['versions'][$packageName]['pretty_version']; + } + if (array_key_exists('aliases', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']); + } + if (array_key_exists('replaced', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); + } + if (array_key_exists('provided', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); + } + + return implode(' || ', $ranges); + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['version'])) { + return null; + } + + return $installed['versions'][$packageName]['version']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getPrettyVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['pretty_version'])) { + return null; + } + + return $installed['versions'][$packageName]['pretty_version']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference + */ + public static function getReference($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['reference'])) { + return null; + } + + return $installed['versions'][$packageName]['reference']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path. + */ + public static function getInstallPath($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @return array + * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool} + */ + public static function getRootPackage() + { + $installed = self::getInstalled(); + + return $installed[0]['root']; + } + + /** + * Returns the raw installed.php data for custom implementations + * + * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. + * @return array[] + * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} + */ + public static function getRawData() + { + @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED); + + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (substr(__DIR__, -8, 1) !== 'C') { + self::$installed = include __DIR__ . '/installed.php'; + } else { + self::$installed = array(); + } + } + + return self::$installed; + } + + /** + * Returns the raw data of all installed.php which are currently loaded for custom implementations + * + * @return array[] + * @psalm-return list}> + */ + public static function getAllRawData() + { + return self::getInstalled(); + } + + /** + * Lets you reload the static array from another file + * + * This is only useful for complex integrations in which a project needs to use + * this class but then also needs to execute another project's autoloader in process, + * and wants to ensure both projects have access to their version of installed.php. + * + * A typical case would be PHPUnit, where it would need to make sure it reads all + * the data it needs from this class, then call reload() with + * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure + * the project in which it runs can then also use this class safely, without + * interference between PHPUnit's dependencies and the project's dependencies. + * + * @param array[] $data A vendor/composer/installed.php data set + * @return void + * + * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $data + */ + public static function reload($data) + { + self::$installed = $data; + self::$installedByVendor = array(); + + // when using reload, we disable the duplicate protection to ensure that self::$installed data is + // always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not, + // so we have to assume it does not, and that may result in duplicate data being returned when listing + // all installed packages for example + self::$installedIsLocalDir = false; + } + + /** + * @return string + */ + private static function getSelfDir() + { + if (self::$selfDir === null) { + self::$selfDir = strtr(__DIR__, '\\', '/'); + } + + return self::$selfDir; + } + + /** + * @return array[] + * @psalm-return list}> + */ + private static function getInstalled() + { + if (null === self::$canGetVendors) { + self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); + } + + $installed = array(); + $copiedLocalDir = false; + + if (self::$canGetVendors) { + $selfDir = self::getSelfDir(); + foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { + $vendorDir = strtr($vendorDir, '\\', '/'); + if (isset(self::$installedByVendor[$vendorDir])) { + $installed[] = self::$installedByVendor[$vendorDir]; + } elseif (is_file($vendorDir.'/composer/installed.php')) { + /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ + $required = require $vendorDir.'/composer/installed.php'; + self::$installedByVendor[$vendorDir] = $required; + $installed[] = $required; + if (self::$installed === null && $vendorDir.'/composer' === $selfDir) { + self::$installed = $required; + self::$installedIsLocalDir = true; + } + } + if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) { + $copiedLocalDir = true; + } + } + } + + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (substr(__DIR__, -8, 1) !== 'C') { + /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ + $required = require __DIR__ . '/installed.php'; + self::$installed = $required; + } else { + self::$installed = array(); + } + } + + if (self::$installed !== array() && !$copiedLocalDir) { + $installed[] = self::$installed; + } + + return $installed; + } +} diff --git a/datamodels/2.x/combodo-data-feature-removal/vendor/composer/LICENSE b/datamodels/2.x/combodo-data-feature-removal/vendor/composer/LICENSE new file mode 100644 index 0000000000..f27399a042 --- /dev/null +++ b/datamodels/2.x/combodo-data-feature-removal/vendor/composer/LICENSE @@ -0,0 +1,21 @@ + +Copyright (c) Nils Adermann, Jordi Boggiano + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/datamodels/2.x/combodo-data-feature-removal/vendor/composer/autoload_classmap.php b/datamodels/2.x/combodo-data-feature-removal/vendor/composer/autoload_classmap.php new file mode 100644 index 0000000000..8a38a84587 --- /dev/null +++ b/datamodels/2.x/combodo-data-feature-removal/vendor/composer/autoload_classmap.php @@ -0,0 +1,21 @@ + $baseDir . '/src/Controller/DataFeatureRemovalController.php', + 'Combodo\\iTop\\DataFeatureRemoval\\Entity\\DataCleanupSummaryEntity' => $baseDir . '/src/Entity/DataCleanupSummaryEntity.php', + 'Combodo\\iTop\\DataFeatureRemoval\\Helper\\DataFeatureRemovalConfig' => $baseDir . '/src/Helper/DataFeatureRemovalConfig.php', + 'Combodo\\iTop\\DataFeatureRemoval\\Helper\\DataFeatureRemovalException' => $baseDir . '/src/Helper/DataFeatureRemovalException.php', + 'Combodo\\iTop\\DataFeatureRemoval\\Helper\\DataFeatureRemovalHelper' => $baseDir . '/src/Helper/DataFeatureRemovalHelper.php', + 'Combodo\\iTop\\DataFeatureRemoval\\Helper\\DataFeatureRemovalLog' => $baseDir . '/src/Helper/DataFeatureRemovalLog.php', + 'Combodo\\iTop\\DataFeatureRemoval\\Service\\DataCleanupService' => $baseDir . '/src/Service/DataCleanupService.php', + 'Combodo\\iTop\\DataFeatureRemoval\\Service\\DataFeatureRemoverExtensionService' => $baseDir . '/src/Service/DataFeatureRemoverExtensionService.php', + 'Combodo\\iTop\\DataFeatureRemoval\\Service\\ObjectService' => $baseDir . '/src/Service/ObjectService.php', + 'Combodo\\iTop\\DataFeatureRemoval\\Service\\ObjectServiceSummary' => $baseDir . '/src/Service/ObjectServiceSummary.php', + 'Combodo\\iTop\\DataFeatureRemoval\\Service\\iObjectService' => $baseDir . '/src/Service/iObjectService.php', + 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php', +); diff --git a/datamodels/2.x/combodo-data-feature-removal/vendor/composer/autoload_namespaces.php b/datamodels/2.x/combodo-data-feature-removal/vendor/composer/autoload_namespaces.php new file mode 100644 index 0000000000..15a2ff3ad6 --- /dev/null +++ b/datamodels/2.x/combodo-data-feature-removal/vendor/composer/autoload_namespaces.php @@ -0,0 +1,9 @@ + array($baseDir . '/src'), +); diff --git a/datamodels/2.x/combodo-data-feature-removal/vendor/composer/autoload_real.php b/datamodels/2.x/combodo-data-feature-removal/vendor/composer/autoload_real.php new file mode 100644 index 0000000000..c766acb7d1 --- /dev/null +++ b/datamodels/2.x/combodo-data-feature-removal/vendor/composer/autoload_real.php @@ -0,0 +1,37 @@ +setClassMapAuthoritative(true); + $loader->register(true); + + return $loader; + } +} diff --git a/datamodels/2.x/combodo-data-feature-removal/vendor/composer/autoload_static.php b/datamodels/2.x/combodo-data-feature-removal/vendor/composer/autoload_static.php new file mode 100644 index 0000000000..94e5a3715f --- /dev/null +++ b/datamodels/2.x/combodo-data-feature-removal/vendor/composer/autoload_static.php @@ -0,0 +1,47 @@ + + array ( + 'Combodo\\iTop\\DataFeatureRemoval\\' => 32, + ), + ); + + public static $prefixDirsPsr4 = array ( + 'Combodo\\iTop\\DataFeatureRemoval\\' => + array ( + 0 => __DIR__ . '/../..' . '/src', + ), + ); + + public static $classMap = array ( + 'Combodo\\iTop\\DataFeatureRemoval\\Controller\\DataFeatureRemovalController' => __DIR__ . '/../..' . '/src/Controller/DataFeatureRemovalController.php', + 'Combodo\\iTop\\DataFeatureRemoval\\Entity\\DataCleanupSummaryEntity' => __DIR__ . '/../..' . '/src/Entity/DataCleanupSummaryEntity.php', + 'Combodo\\iTop\\DataFeatureRemoval\\Helper\\DataFeatureRemovalConfig' => __DIR__ . '/../..' . '/src/Helper/DataFeatureRemovalConfig.php', + 'Combodo\\iTop\\DataFeatureRemoval\\Helper\\DataFeatureRemovalException' => __DIR__ . '/../..' . '/src/Helper/DataFeatureRemovalException.php', + 'Combodo\\iTop\\DataFeatureRemoval\\Helper\\DataFeatureRemovalHelper' => __DIR__ . '/../..' . '/src/Helper/DataFeatureRemovalHelper.php', + 'Combodo\\iTop\\DataFeatureRemoval\\Helper\\DataFeatureRemovalLog' => __DIR__ . '/../..' . '/src/Helper/DataFeatureRemovalLog.php', + 'Combodo\\iTop\\DataFeatureRemoval\\Service\\DataCleanupService' => __DIR__ . '/../..' . '/src/Service/DataCleanupService.php', + 'Combodo\\iTop\\DataFeatureRemoval\\Service\\DataFeatureRemoverExtensionService' => __DIR__ . '/../..' . '/src/Service/DataFeatureRemoverExtensionService.php', + 'Combodo\\iTop\\DataFeatureRemoval\\Service\\ObjectService' => __DIR__ . '/../..' . '/src/Service/ObjectService.php', + 'Combodo\\iTop\\DataFeatureRemoval\\Service\\ObjectServiceSummary' => __DIR__ . '/../..' . '/src/Service/ObjectServiceSummary.php', + 'Combodo\\iTop\\DataFeatureRemoval\\Service\\iObjectService' => __DIR__ . '/../..' . '/src/Service/iObjectService.php', + 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixLengthsPsr4 = ComposerStaticInit4f96a7199e2c0d90e547333758b26464::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInit4f96a7199e2c0d90e547333758b26464::$prefixDirsPsr4; + $loader->classMap = ComposerStaticInit4f96a7199e2c0d90e547333758b26464::$classMap; + + }, null, ClassLoader::class); + } +} diff --git a/datamodels/2.x/combodo-data-feature-removal/vendor/composer/installed.json b/datamodels/2.x/combodo-data-feature-removal/vendor/composer/installed.json new file mode 100644 index 0000000000..87fda747e6 --- /dev/null +++ b/datamodels/2.x/combodo-data-feature-removal/vendor/composer/installed.json @@ -0,0 +1,5 @@ +{ + "packages": [], + "dev": true, + "dev-package-names": [] +} diff --git a/datamodels/2.x/combodo-data-feature-removal/vendor/composer/installed.php b/datamodels/2.x/combodo-data-feature-removal/vendor/composer/installed.php new file mode 100644 index 0000000000..e7242a61e0 --- /dev/null +++ b/datamodels/2.x/combodo-data-feature-removal/vendor/composer/installed.php @@ -0,0 +1,23 @@ + array( + 'name' => 'combodo/combodo-data-feature-removal', + 'pretty_version' => 'dev-develop', + 'version' => 'dev-develop', + 'reference' => '19bbf6759bb4f6f5814d9ec1b0b5514208efc0b2', + 'type' => 'itop-extension', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'dev' => true, + ), + 'versions' => array( + 'combodo/combodo-data-feature-removal' => array( + 'pretty_version' => 'dev-develop', + 'version' => 'dev-develop', + 'reference' => '19bbf6759bb4f6f5814d9ec1b0b5514208efc0b2', + 'type' => 'itop-extension', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'dev_requirement' => false, + ), + ), +); diff --git a/datamodels/2.x/combodo-db-tools/src/Service/DBToolsUtils.php b/datamodels/2.x/combodo-db-tools/src/Service/DBToolsUtils.php index 09dcf4824f..735f714d0a 100644 --- a/datamodels/2.x/combodo-db-tools/src/Service/DBToolsUtils.php +++ b/datamodels/2.x/combodo-db-tools/src/Service/DBToolsUtils.php @@ -10,6 +10,7 @@ namespace Combodo\iTop\DBTools\Service; use CMDBSource; use DBObjectSearch; use DBObjectSet; +use IssueLog; class DBToolsUtils { diff --git a/datamodels/2.x/installation.xml b/datamodels/2.x/installation.xml index bbaf745a8c..2b5185b355 100755 --- a/datamodels/2.x/installation.xml +++ b/datamodels/2.x/installation.xml @@ -27,12 +27,6 @@ combodo-backoffice-fullmoon-protanopia-deuteranopia-theme combodo-backoffice-fullmoon-tritanopia-theme itop-themes-compat - combodo-my-account - combodo-my-account-user-info - combodo-oauth2-client - itop-attribute-class-set - itop-attribute-encrypted-password - itop-ui-copypaste true @@ -241,7 +235,7 @@ itop-problem-mgmt Problem Management - Select this option track "Problems" in iTop. + Select this option to track "Problems" in iTop. itop-problem-mgmt diff --git a/datamodels/2.x/itop-attachments/src/Trigger/TriggerOnAttachmentDelete.php b/datamodels/2.x/itop-attachments/src/Trigger/TriggerOnAttachmentDelete.php index 34d66a692f..9c31c3c3a6 100644 --- a/datamodels/2.x/itop-attachments/src/Trigger/TriggerOnAttachmentDelete.php +++ b/datamodels/2.x/itop-attachments/src/Trigger/TriggerOnAttachmentDelete.php @@ -36,7 +36,6 @@ class TriggerOnAttachmentDelete extends TriggerOnObject MetaModel::Init_InheritAttributes(); MetaModel::Init_AddAttribute(new AttributeBoolean("file_in_email", ["sql" => 'file_in_email', "is_null_allowed" => false, "default_value" => 'true', "allowed_values" => null, "depends_on" => [], "always_load_in_tables" => false])); - // Display lists MetaModel::Init_SetZListItems('details', ['description', 'context', 'filter', 'action_list', 'target_class','file_in_email']); // Attributes to be displayed for the complete details MetaModel::Init_SetZListItems('list', ['finalclass', 'target_class']); // Attributes to be displayed for a list diff --git a/datamodels/2.x/itop-backup/ajax.backup.php b/datamodels/2.x/itop-backup/ajax.backup.php index 35dfd75a02..73a39d5154 100644 --- a/datamodels/2.x/itop-backup/ajax.backup.php +++ b/datamodels/2.x/itop-backup/ajax.backup.php @@ -131,7 +131,7 @@ try { $oPage = new JsonPage(); $oPage->SetOutputDataOnly(true); - $sEnvironment = utils::ReadParam('environment', 'production', false, 'raw_data'); + $sEnvironment = utils::ReadParam('environment', ITOP_DEFAULT_ENV, false, 'raw_data'); $oRestoreMutex = new iTopMutex('restore.'.$sEnvironment); if ($oRestoreMutex->IsLocked()) { DisplayErrorAndDie($oPage, '

'.Dict::S('bkp-restore-running').'

'); @@ -156,7 +156,7 @@ try { require_once(APPROOT.'/setup/backup.class.inc.php'); require_once(__DIR__.'/dbrestore.class.inc.php'); - $sEnvironment = utils::ReadParam('environment', 'production', false, 'raw_data'); + $sEnvironment = utils::ReadParam('environment', ITOP_DEFAULT_ENV, false, 'raw_data'); try { set_time_limit(0); diff --git a/datamodels/2.x/itop-backup/dbrestore.class.inc.php b/datamodels/2.x/itop-backup/dbrestore.class.inc.php index e8ffe53d1f..3a3ccbd1a9 100644 --- a/datamodels/2.x/itop-backup/dbrestore.class.inc.php +++ b/datamodels/2.x/itop-backup/dbrestore.class.inc.php @@ -97,7 +97,7 @@ class DBRestore extends DBBackup * * @uses \RunTimeEnvironment::CompileFrom() */ - public function RestoreFromCompressedBackup($sFile, $sEnvironment = 'production') + public function RestoreFromCompressedBackup($sFile, $sEnvironment = ITOP_DEFAULT_ENV) { $oRestoreMutex = new iTopMutex('restore.'.$sEnvironment); IssueLog::Info("Backup Restore - Acquiring the LOCK 'restore.$sEnvironment'"); diff --git a/datamodels/2.x/itop-backup/restore.php b/datamodels/2.x/itop-backup/restore.php index 395f1c15c5..bf18435c28 100644 --- a/datamodels/2.x/itop-backup/restore.php +++ b/datamodels/2.x/itop-backup/restore.php @@ -126,7 +126,7 @@ function ExecuteMainOperation($oP) if (MetaModel::GetConfig()->Get('demo_mode')) { $oP->p("Sorry, iTop is in demonstration mode: the feature is disabled"); } else { - $sEnvironment = utils::ReadParam('environment', 'production', false, 'raw_data'); + $sEnvironment = utils::ReadParam('environment', ITOP_DEFAULT_ENV, false, 'raw_data'); $oRestore->RestoreFromCompressedBackup($sBackupFile, $sEnvironment); } } diff --git a/datamodels/2.x/itop-core-update/dictionaries/cs.dict.itop-core-update.php b/datamodels/2.x/itop-core-update/dictionaries/cs.dict.itop-core-update.php index 55d49ed700..a630ee904e 100644 --- a/datamodels/2.x/itop-core-update/dictionaries/cs.dict.itop-core-update.php +++ b/datamodels/2.x/itop-core-update/dictionaries/cs.dict.itop-core-update.php @@ -44,8 +44,8 @@ Dict::Add('CS CZ', 'Czech', 'Čeština', [ 'iTopUpdate:UI:Setup' => ITOP_APPLICATION_SHORT.' Setup~~', 'iTopUpdate:UI:History' => 'Versions History~~', 'iTopUpdate:UI:Progress' => 'Progress of the upgrade~~', - 'iTopUpdate:UI:DoBackup:Label' => 'Záložní soubory a databáze', - 'iTopUpdate:UI:DoBackup:Warning' => 'Backup is not recommended due to limited available disk space~~', + 'iTopUpdate:UI:Backup:Label' => 'Záložní soubory a databáze', + 'iTopUpdate:UI:Backup:Warning' => 'Backup is not recommended due to limited available disk space~~', 'iTopUpdate:UI:DiskFreeSpace' => 'Volné místo', 'iTopUpdate:UI:ItopDiskSpace' => ITOP_APPLICATION_SHORT.' disk space~~', 'iTopUpdate:UI:DBDiskSpace' => 'Prostor obsazený Databází', diff --git a/datamodels/2.x/itop-core-update/dictionaries/da.dict.itop-core-update.php b/datamodels/2.x/itop-core-update/dictionaries/da.dict.itop-core-update.php index 0e358f8178..ad3087ee98 100644 --- a/datamodels/2.x/itop-core-update/dictionaries/da.dict.itop-core-update.php +++ b/datamodels/2.x/itop-core-update/dictionaries/da.dict.itop-core-update.php @@ -44,8 +44,8 @@ Dict::Add('DA DA', 'Danish', 'Dansk', [ 'iTopUpdate:UI:Setup' => ITOP_APPLICATION_SHORT.' Setup~~', 'iTopUpdate:UI:History' => 'Versions History~~', 'iTopUpdate:UI:Progress' => 'Progress of the upgrade~~', - 'iTopUpdate:UI:DoBackup:Label' => 'Backup files and database~~', - 'iTopUpdate:UI:DoBackup:Warning' => 'Backup is not recommended due to limited available disk space~~', + 'iTopUpdate:UI:Backup:Label' => 'Backup files and database~~', + 'iTopUpdate:UI:Backup:Warning' => 'Backup is not recommended due to limited available disk space~~', 'iTopUpdate:UI:DiskFreeSpace' => 'Disk free space~~', 'iTopUpdate:UI:ItopDiskSpace' => ITOP_APPLICATION_SHORT.' disk space~~', 'iTopUpdate:UI:DBDiskSpace' => 'Database disk space~~', diff --git a/datamodels/2.x/itop-core-update/dictionaries/de.dict.itop-core-update.php b/datamodels/2.x/itop-core-update/dictionaries/de.dict.itop-core-update.php index 664cc6c92d..a3bbad4ce2 100644 --- a/datamodels/2.x/itop-core-update/dictionaries/de.dict.itop-core-update.php +++ b/datamodels/2.x/itop-core-update/dictionaries/de.dict.itop-core-update.php @@ -44,8 +44,8 @@ Dict::Add('DE DE', 'German', 'Deutsch', [ 'iTopUpdate:UI:Setup' => ITOP_APPLICATION_SHORT.' Setup', 'iTopUpdate:UI:History' => 'Versionshistorie', 'iTopUpdate:UI:Progress' => 'Upgradefortschritt', - 'iTopUpdate:UI:DoBackup:Label' => 'Backup von Dateien und Datenbank', - 'iTopUpdate:UI:DoBackup:Warning' => 'Wegen geringem verbleibenden Speicherplatz sollte kein Backup mehr erzeugt werden.', + 'iTopUpdate:UI:Backup:Label' => 'Backup von Dateien und Datenbank', + 'iTopUpdate:UI:Backup:Warning' => 'Wegen geringem verbleibenden Speicherplatz sollte kein Backup mehr erzeugt werden.', 'iTopUpdate:UI:DiskFreeSpace' => 'Freier Speicherplatz', 'iTopUpdate:UI:ItopDiskSpace' => ITOP_APPLICATION_SHORT.' Speicherplatz', 'iTopUpdate:UI:DBDiskSpace' => 'Datenbankgröße', diff --git a/datamodels/2.x/itop-core-update/dictionaries/en.dict.itop-core-update.php b/datamodels/2.x/itop-core-update/dictionaries/en.dict.itop-core-update.php index 03b081061e..12b3122479 100644 --- a/datamodels/2.x/itop-core-update/dictionaries/en.dict.itop-core-update.php +++ b/datamodels/2.x/itop-core-update/dictionaries/en.dict.itop-core-update.php @@ -59,8 +59,8 @@ Dict::Add('EN US', 'English', 'English', [ 'iTopUpdate:UI:History' => 'Versions History', 'iTopUpdate:UI:Progress' => 'Progress of the upgrade', - 'iTopUpdate:UI:DoBackup:Label' => 'Backup files and database', - 'iTopUpdate:UI:DoBackup:Warning' => 'Backup is not recommended due to limited available disk space', + 'iTopUpdate:UI:Backup:Label' => 'Backup files and database', + 'iTopUpdate:UI:Backup:Warning' => 'Backup is not recommended due to limited available disk space', 'iTopUpdate:UI:DiskFreeSpace' => 'Disk free space', 'iTopUpdate:UI:ItopDiskSpace' => ITOP_APPLICATION_SHORT.' disk space', diff --git a/datamodels/2.x/itop-core-update/dictionaries/en_gb.dict.itop-core-update.php b/datamodels/2.x/itop-core-update/dictionaries/en_gb.dict.itop-core-update.php index 25eb1a825a..33ef89bf0b 100644 --- a/datamodels/2.x/itop-core-update/dictionaries/en_gb.dict.itop-core-update.php +++ b/datamodels/2.x/itop-core-update/dictionaries/en_gb.dict.itop-core-update.php @@ -59,8 +59,8 @@ Dict::Add('EN GB', 'British English', 'British English', [ 'iTopUpdate:UI:History' => 'Versions History', 'iTopUpdate:UI:Progress' => 'Progress of the upgrade', - 'iTopUpdate:UI:DoBackup:Label' => 'Backup files and database', - 'iTopUpdate:UI:DoBackup:Warning' => 'Backup is not recommended due to limited available disk space', + 'iTopUpdate:UI:Backup:Label' => 'Backup files and database', + 'iTopUpdate:UI:Backup:Warning' => 'Backup is not recommended due to limited available disk space', 'iTopUpdate:UI:DiskFreeSpace' => 'Disk free space', 'iTopUpdate:UI:ItopDiskSpace' => ITOP_APPLICATION_SHORT.' disk space', diff --git a/datamodels/2.x/itop-core-update/dictionaries/es_cr.dict.itop-core-update.php b/datamodels/2.x/itop-core-update/dictionaries/es_cr.dict.itop-core-update.php index 89f6852a10..bdd18f2a35 100644 --- a/datamodels/2.x/itop-core-update/dictionaries/es_cr.dict.itop-core-update.php +++ b/datamodels/2.x/itop-core-update/dictionaries/es_cr.dict.itop-core-update.php @@ -42,8 +42,8 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', [ 'iTopUpdate:UI:Setup' => 'Configuración '.ITOP_APPLICATION_SHORT, 'iTopUpdate:UI:History' => 'Historial de versiones', 'iTopUpdate:UI:Progress' => 'Progreso de actualización', - 'iTopUpdate:UI:DoBackup:Label' => 'Respaldo de archivos y base de datos', - 'iTopUpdate:UI:DoBackup:Warning' => 'El respaldo no está recomendado por el limitado espacio en el dispositivo', + 'iTopUpdate:UI:Backup:Label' => 'Respaldo de archivos y base de datos', + 'iTopUpdate:UI:Backup:Warning' => 'El respaldo no está recomendado por el limitado espacio en el dispositivo', 'iTopUpdate:UI:DiskFreeSpace' => 'Espacio libre en el dispositivo', 'iTopUpdate:UI:ItopDiskSpace' => 'Espacio en disco de '.ITOP_APPLICATION_SHORT, 'iTopUpdate:UI:DBDiskSpace' => 'Espacio en disco de base de datos', diff --git a/datamodels/2.x/itop-core-update/dictionaries/fr.dict.itop-core-update.php b/datamodels/2.x/itop-core-update/dictionaries/fr.dict.itop-core-update.php index ec69140c01..94286172f8 100644 --- a/datamodels/2.x/itop-core-update/dictionaries/fr.dict.itop-core-update.php +++ b/datamodels/2.x/itop-core-update/dictionaries/fr.dict.itop-core-update.php @@ -44,8 +44,8 @@ Dict::Add('FR FR', 'French', 'Français', [ 'iTopUpdate:UI:Setup' => ITOP_APPLICATION_SHORT.' Setup', 'iTopUpdate:UI:History' => 'Historique des versions', 'iTopUpdate:UI:Progress' => 'Progression de la mise à jour', - 'iTopUpdate:UI:DoBackup:Label' => 'Sauvegarde de la base de données', - 'iTopUpdate:UI:DoBackup:Warning' => 'La sauvegarde n\'est pas conseillée à cause du manque de place disque disponible', + 'iTopUpdate:UI:Backup:Label' => 'Sauvegarde de la base de données', + 'iTopUpdate:UI:Backup:Warning' => 'La sauvegarde n\'est pas conseillée à cause du manque de place disque disponible', 'iTopUpdate:UI:DiskFreeSpace' => 'Taille disque disponible', 'iTopUpdate:UI:ItopDiskSpace' => 'Taille disque utilisée par l\'application', 'iTopUpdate:UI:DBDiskSpace' => 'Taille disque utilisée par la base de données', diff --git a/datamodels/2.x/itop-core-update/dictionaries/hu.dict.itop-core-update.php b/datamodels/2.x/itop-core-update/dictionaries/hu.dict.itop-core-update.php index 0573fa06af..3fd1c16348 100644 --- a/datamodels/2.x/itop-core-update/dictionaries/hu.dict.itop-core-update.php +++ b/datamodels/2.x/itop-core-update/dictionaries/hu.dict.itop-core-update.php @@ -44,8 +44,8 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', [ 'iTopUpdate:UI:Setup' => ITOP_APPLICATION_SHORT.' Setup~~', 'iTopUpdate:UI:History' => 'Verziótörténet', 'iTopUpdate:UI:Progress' => 'A frissítés folyamata', - 'iTopUpdate:UI:DoBackup:Label' => 'Mentés fájlok és adatbázis', - 'iTopUpdate:UI:DoBackup:Warning' => 'A biztonsági mentés nem ajánlott a korlátozottan rendelkezésre álló lemezterület miatt.', + 'iTopUpdate:UI:Backup:Label' => 'Mentés fájlok és adatbázis', + 'iTopUpdate:UI:Backup:Warning' => 'A biztonsági mentés nem ajánlott a korlátozottan rendelkezésre álló lemezterület miatt.', 'iTopUpdate:UI:DiskFreeSpace' => 'Lemez szabad terület', 'iTopUpdate:UI:ItopDiskSpace' => ITOP_APPLICATION_SHORT.' lemezterület', 'iTopUpdate:UI:DBDiskSpace' => 'Adatbázis lemezterület', diff --git a/datamodels/2.x/itop-core-update/dictionaries/it.dict.itop-core-update.php b/datamodels/2.x/itop-core-update/dictionaries/it.dict.itop-core-update.php index 5f98580d06..88ce20c31b 100644 --- a/datamodels/2.x/itop-core-update/dictionaries/it.dict.itop-core-update.php +++ b/datamodels/2.x/itop-core-update/dictionaries/it.dict.itop-core-update.php @@ -44,8 +44,8 @@ Dict::Add('IT IT', 'Italian', 'Italiano', [ 'iTopUpdate:UI:Setup' => ITOP_APPLICATION_SHORT.' Setup', 'iTopUpdate:UI:History' => 'Storia delle Versioni', 'iTopUpdate:UI:Progress' => 'Progresso dell\'aggiornamento', - 'iTopUpdate:UI:DoBackup:Label' => 'Backup dei file e del database', - 'iTopUpdate:UI:DoBackup:Warning' => 'Backup non raccomandato a causa dello spazio su disco limitato disponibile', + 'iTopUpdate:UI:Backup:Label' => 'Backup dei file e del database', + 'iTopUpdate:UI:Backup:Warning' => 'Backup non raccomandato a causa dello spazio su disco limitato disponibile', 'iTopUpdate:UI:DiskFreeSpace' => 'Spazio libero su disco', 'iTopUpdate:UI:ItopDiskSpace' => ITOP_APPLICATION_SHORT.' spazio su disco', 'iTopUpdate:UI:DBDiskSpace' => 'Spazio su disco del Database', diff --git a/datamodels/2.x/itop-core-update/dictionaries/ja.dict.itop-core-update.php b/datamodels/2.x/itop-core-update/dictionaries/ja.dict.itop-core-update.php index ad9aad2c0a..78ba3904fb 100644 --- a/datamodels/2.x/itop-core-update/dictionaries/ja.dict.itop-core-update.php +++ b/datamodels/2.x/itop-core-update/dictionaries/ja.dict.itop-core-update.php @@ -44,8 +44,8 @@ Dict::Add('JA JP', 'Japanese', '日本語', [ 'iTopUpdate:UI:Setup' => ITOP_APPLICATION_SHORT.' Setup~~', 'iTopUpdate:UI:History' => 'Versions History~~', 'iTopUpdate:UI:Progress' => 'Progress of the upgrade~~', - 'iTopUpdate:UI:DoBackup:Label' => 'Backup files and database~~', - 'iTopUpdate:UI:DoBackup:Warning' => 'Backup is not recommended due to limited available disk space~~', + 'iTopUpdate:UI:Backup:Label' => 'Backup files and database~~', + 'iTopUpdate:UI:Backup:Warning' => 'Backup is not recommended due to limited available disk space~~', 'iTopUpdate:UI:DiskFreeSpace' => 'Disk free space~~', 'iTopUpdate:UI:ItopDiskSpace' => ITOP_APPLICATION_SHORT.' disk space~~', 'iTopUpdate:UI:DBDiskSpace' => 'Database disk space~~', diff --git a/datamodels/2.x/itop-core-update/dictionaries/nl.dict.itop-core-update.php b/datamodels/2.x/itop-core-update/dictionaries/nl.dict.itop-core-update.php index 271ea56908..6270d66872 100644 --- a/datamodels/2.x/itop-core-update/dictionaries/nl.dict.itop-core-update.php +++ b/datamodels/2.x/itop-core-update/dictionaries/nl.dict.itop-core-update.php @@ -45,8 +45,8 @@ Dict::Add('NL NL', 'Dutch', 'Nederlands', [ 'iTopUpdate:UI:Setup' => ITOP_APPLICATION_SHORT.' setup', 'iTopUpdate:UI:History' => 'Versiegeschiedenis', 'iTopUpdate:UI:Progress' => 'Voortgang van de upgrade', - 'iTopUpdate:UI:DoBackup:Label' => 'Maak een backup van de bestanden en database', - 'iTopUpdate:UI:DoBackup:Warning' => 'Een backup maken wordt afgeraden doordat er weinig schijfruimte is', + 'iTopUpdate:UI:Backup:Label' => 'Maak een backup van de bestanden en database', + 'iTopUpdate:UI:Backup:Warning' => 'Een backup maken wordt afgeraden doordat er weinig schijfruimte is', 'iTopUpdate:UI:DiskFreeSpace' => 'Vrije schijfruimte', 'iTopUpdate:UI:ItopDiskSpace' => ITOP_APPLICATION_SHORT.' schijfgebruik', 'iTopUpdate:UI:DBDiskSpace' => 'Database schijfgebruik', diff --git a/datamodels/2.x/itop-core-update/dictionaries/pl.dict.itop-core-update.php b/datamodels/2.x/itop-core-update/dictionaries/pl.dict.itop-core-update.php index afcb92c595..376ad37d4f 100644 --- a/datamodels/2.x/itop-core-update/dictionaries/pl.dict.itop-core-update.php +++ b/datamodels/2.x/itop-core-update/dictionaries/pl.dict.itop-core-update.php @@ -44,8 +44,8 @@ Dict::Add('PL PL', 'Polish', 'Polski', [ 'iTopUpdate:UI:Action' => 'Aktualizacja', 'iTopUpdate:UI:Setup' => 'Konfiguracja '.ITOP_APPLICATION_SHORT, 'iTopUpdate:UI:History' => 'Historia wersji', 'iTopUpdate:UI:Progress' => 'Progress of the upgrade', - 'iTopUpdate:UI:DoBackup:Label' => 'Kopie zapasowe plików i bazy danych', - 'iTopUpdate:UI:DoBackup:Warning' => 'Tworzenie kopii zapasowych nie jest zalecane ze względu na ograniczoną ilość wolnego miejsca na dysku', + 'iTopUpdate:UI:Backup:Label' => 'Kopie zapasowe plików i bazy danych', + 'iTopUpdate:UI:Backup:Warning' => 'Tworzenie kopii zapasowych nie jest zalecane ze względu na ograniczoną ilość wolnego miejsca na dysku', 'iTopUpdate:UI:DiskFreeSpace' => 'Wolne miejsce na dysku', 'iTopUpdate:UI:ItopDiskSpace' => 'Przestrzeń dyskowa '.ITOP_APPLICATION_SHORT, 'iTopUpdate:UI:DBDiskSpace' => 'Przestrzeń dyskowa bazy danych', 'iTopUpdate:UI:FileUploadMaxSize' => 'Maksymalny rozmiar przesyłanego pliku', diff --git a/datamodels/2.x/itop-core-update/dictionaries/pt_br.dict.itop-core-update.php b/datamodels/2.x/itop-core-update/dictionaries/pt_br.dict.itop-core-update.php index e8bbcd3781..34aa05405e 100644 --- a/datamodels/2.x/itop-core-update/dictionaries/pt_br.dict.itop-core-update.php +++ b/datamodels/2.x/itop-core-update/dictionaries/pt_br.dict.itop-core-update.php @@ -46,8 +46,8 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', [ 'iTopUpdate:UI:Setup' => ITOP_APPLICATION_SHORT.' Setup~~', 'iTopUpdate:UI:History' => 'Versões anteriores', 'iTopUpdate:UI:Progress' => 'Progresso da atualização', - 'iTopUpdate:UI:DoBackup:Label' => 'Backup de arquivos e banco de dados', - 'iTopUpdate:UI:DoBackup:Warning' => 'Backup não recomendado devido ao espaço em disco limitado', + 'iTopUpdate:UI:Backup:Label' => 'Backup de arquivos e banco de dados', + 'iTopUpdate:UI:Backup:Warning' => 'Backup não recomendado devido ao espaço em disco limitado', 'iTopUpdate:UI:DiskFreeSpace' => 'Espaço em disco disponível', 'iTopUpdate:UI:ItopDiskSpace' => 'Espaço em disco do '.ITOP_APPLICATION_SHORT, 'iTopUpdate:UI:DBDiskSpace' => 'Espaço em disco do banco de dados', diff --git a/datamodels/2.x/itop-core-update/dictionaries/ru.dict.itop-core-update.php b/datamodels/2.x/itop-core-update/dictionaries/ru.dict.itop-core-update.php index 2ab106ec12..c8eec3b3e4 100644 --- a/datamodels/2.x/itop-core-update/dictionaries/ru.dict.itop-core-update.php +++ b/datamodels/2.x/itop-core-update/dictionaries/ru.dict.itop-core-update.php @@ -45,8 +45,8 @@ Dict::Add('RU RU', 'Russian', 'Русский', [ 'iTopUpdate:UI:Setup' => ITOP_APPLICATION_SHORT.' Setup~~', 'iTopUpdate:UI:History' => 'История версий', 'iTopUpdate:UI:Progress' => 'Ход обновления', - 'iTopUpdate:UI:DoBackup:Label' => 'Создать резервную копию базы данных', - 'iTopUpdate:UI:DoBackup:Warning' => 'Резервное копирование не рекомендуется из-за ограниченного свободного места на диске', + 'iTopUpdate:UI:Backup:Label' => 'Создать резервную копию базы данных', + 'iTopUpdate:UI:Backup:Warning' => 'Резервное копирование не рекомендуется из-за ограниченного свободного места на диске', 'iTopUpdate:UI:DiskFreeSpace' => 'Доступное дисковое пространство', 'iTopUpdate:UI:ItopDiskSpace' => 'Размер приложения', 'iTopUpdate:UI:DBDiskSpace' => 'Размер базы данных', diff --git a/datamodels/2.x/itop-core-update/dictionaries/sk.dict.itop-core-update.php b/datamodels/2.x/itop-core-update/dictionaries/sk.dict.itop-core-update.php index b5299012b5..18be976b02 100644 --- a/datamodels/2.x/itop-core-update/dictionaries/sk.dict.itop-core-update.php +++ b/datamodels/2.x/itop-core-update/dictionaries/sk.dict.itop-core-update.php @@ -44,8 +44,8 @@ Dict::Add('SK SK', 'Slovak', 'Slovenčina', [ 'iTopUpdate:UI:Setup' => ITOP_APPLICATION_SHORT.' Setup~~', 'iTopUpdate:UI:History' => 'Versions History~~', 'iTopUpdate:UI:Progress' => 'Progress of the upgrade~~', - 'iTopUpdate:UI:DoBackup:Label' => 'Backup files and database~~', - 'iTopUpdate:UI:DoBackup:Warning' => 'Backup is not recommended due to limited available disk space~~', + 'iTopUpdate:UI:Backup:Label' => 'Backup files and database~~', + 'iTopUpdate:UI:Backup:Warning' => 'Backup is not recommended due to limited available disk space~~', 'iTopUpdate:UI:DiskFreeSpace' => 'Disk free space~~', 'iTopUpdate:UI:ItopDiskSpace' => ITOP_APPLICATION_SHORT.' disk space~~', 'iTopUpdate:UI:DBDiskSpace' => 'Database disk space~~', diff --git a/datamodels/2.x/itop-core-update/dictionaries/tr.dict.itop-core-update.php b/datamodels/2.x/itop-core-update/dictionaries/tr.dict.itop-core-update.php index ffc0581935..5c511200ca 100644 --- a/datamodels/2.x/itop-core-update/dictionaries/tr.dict.itop-core-update.php +++ b/datamodels/2.x/itop-core-update/dictionaries/tr.dict.itop-core-update.php @@ -44,8 +44,8 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', [ 'iTopUpdate:UI:Setup' => ITOP_APPLICATION_SHORT.' Setup~~', 'iTopUpdate:UI:History' => 'Versions History~~', 'iTopUpdate:UI:Progress' => 'Progress of the upgrade~~', - 'iTopUpdate:UI:DoBackup:Label' => 'Backup files and database~~', - 'iTopUpdate:UI:DoBackup:Warning' => 'Backup is not recommended due to limited available disk space~~', + 'iTopUpdate:UI:Backup:Label' => 'Backup files and database~~', + 'iTopUpdate:UI:Backup:Warning' => 'Backup is not recommended due to limited available disk space~~', 'iTopUpdate:UI:DiskFreeSpace' => 'Disk free space~~', 'iTopUpdate:UI:ItopDiskSpace' => ITOP_APPLICATION_SHORT.' disk space~~', 'iTopUpdate:UI:DBDiskSpace' => 'Database disk space~~', diff --git a/datamodels/2.x/itop-core-update/dictionaries/zh_cn.dict.itop-core-update.php b/datamodels/2.x/itop-core-update/dictionaries/zh_cn.dict.itop-core-update.php index 21dcedc576..433c7f610a 100644 --- a/datamodels/2.x/itop-core-update/dictionaries/zh_cn.dict.itop-core-update.php +++ b/datamodels/2.x/itop-core-update/dictionaries/zh_cn.dict.itop-core-update.php @@ -55,8 +55,8 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', [ 'iTopUpdate:UI:Setup' => ITOP_APPLICATION_SHORT.'安装', 'iTopUpdate:UI:History' => '版本历史', 'iTopUpdate:UI:Progress' => '升级进度', - 'iTopUpdate:UI:DoBackup:Label' => '备份文件和数据库', - 'iTopUpdate:UI:DoBackup:Warning' => '由于磁盘空间不足, 不建议备份', + 'iTopUpdate:UI:Backup:Label' => '备份文件和数据库', + 'iTopUpdate:UI:Backup:Warning' => '由于磁盘空间不足, 不建议备份', 'iTopUpdate:UI:DiskFreeSpace' => '磁盘剩余空间', 'iTopUpdate:UI:ItopDiskSpace' => ITOP_APPLICATION_SHORT.'的磁盘空间', 'iTopUpdate:UI:DBDiskSpace' => '数据库的磁盘空间', diff --git a/datamodels/2.x/itop-core-update/src/Controller/AjaxController.php b/datamodels/2.x/itop-core-update/src/Controller/AjaxController.php index 34f772dd44..777858e368 100644 --- a/datamodels/2.x/itop-core-update/src/Controller/AjaxController.php +++ b/datamodels/2.x/itop-core-update/src/Controller/AjaxController.php @@ -46,10 +46,6 @@ class AjaxController extends Controller define('MODULESROOT', APPROOT.'env-production/'); } - require_once(MODULESROOT.'itop-core-update/src/Service/RunTimeEnvironmentCoreUpdater.php'); - require_once(MODULESROOT.'itop-core-update/src/Service/CoreUpdater.php'); - require_once(MODULESROOT.'itop-core-update/src/Controller/AjaxController.php'); - MetaModel::LoadConfig(utils::GetConfig()); $sViewPath = MODULESROOT.'itop-core-update/templates'; @@ -246,10 +242,10 @@ class AjaxController extends Controller $iResponseCode = 200; try { $aParams['sAjaxURL'] = utils::GetAbsoluteUrlAppRoot().'/pages/UI.php'; - $oConfig = new Config(APPCONF.'production'.'/'.ITOP_CONFIG_FILE); - $oEnvironment = new RunTimeEnvironment('production'); + $oConfig = new Config(APPCONF.ITOP_DEFAULT_ENV.'/'.ITOP_CONFIG_FILE); + $oEnvironment = new RunTimeEnvironment(ITOP_DEFAULT_ENV); $oEnvironment->WriteConfigFileSafe($oConfig); - $oEnvironment->CompileFrom('production'); + $oEnvironment->CompileFrom(ITOP_DEFAULT_ENV); } catch (Exception $e) { IssueLog::Error('RebuildToolkitEnvironment: '.$e->getMessage()); $aParams['sError'] = $e->getMessage(); diff --git a/datamodels/2.x/itop-core-update/src/Service/CoreUpdater.php b/datamodels/2.x/itop-core-update/src/Service/CoreUpdater.php index 05a1f43a7c..31b56e074b 100644 --- a/datamodels/2.x/itop-core-update/src/Service/CoreUpdater.php +++ b/datamodels/2.x/itop-core-update/src/Service/CoreUpdater.php @@ -89,10 +89,10 @@ final class CoreUpdater // Compile code SetupLog::Info('itop-core-update: Start checking compilation'); - $sFinalEnv = 'production'; + $sFinalEnv = ITOP_DEFAULT_ENV; $oRuntimeEnv = new RunTimeEnvironmentCoreUpdater($sFinalEnv, false); $oRuntimeEnv->CheckDirectories($sFinalEnv); - $oRuntimeEnv->CompileFrom('production'); + $oRuntimeEnv->CompileFrom($sFinalEnv); $oRuntimeEnv->Rollback(); @@ -117,10 +117,10 @@ final class CoreUpdater // Compile code SetupLog::Info('itop-core-update: Start compilation'); - $sFinalEnv = 'production'; + $sFinalEnv = ITOP_DEFAULT_ENV; $oRuntimeEnv = new RunTimeEnvironmentCoreUpdater($sFinalEnv, true); $oRuntimeEnv->CheckDirectories($sFinalEnv); - $oRuntimeEnv->CompileFrom('production'); + $oRuntimeEnv->CompileFrom(ITOP_DEFAULT_ENV); SetupLog::Info('itop-core-update: Compilation done'); } catch (Exception $e) { @@ -142,7 +142,7 @@ final class CoreUpdater try { SetupLog::Info('itop-core-update: Start Update database'); - $sFinalEnv = 'production'; + $sFinalEnv = ITOP_DEFAULT_ENV; $oRuntimeEnv = new RunTimeEnvironmentCoreUpdater($sFinalEnv, true); $oConfig = $oRuntimeEnv->MakeConfigFile($sFinalEnv.' (built on '.date('Y-m-d').')'); $oConfig->Set('access_mode', ACCESS_FULL); @@ -155,21 +155,13 @@ final class CoreUpdater APPROOT.'extensions', ]; $aAvailableModules = $oRuntimeEnv->AnalyzeInstallation($oConfig, $aDirsToScanForModules); - $aSelectedModules = []; - foreach ($aAvailableModules as $sModuleId => $aModule) { - if (($sModuleId == ROOT_MODULE) || ($sModuleId == DATAMODEL_MODULE)) { - continue; - } else { - $aSelectedModules[] = $sModuleId; - } - } - $oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'BeforeDatabaseCreation'); + $oRuntimeEnv->CallInstallerHandlers($aAvailableModules, 'BeforeDatabaseCreation'); $oRuntimeEnv->CreateDatabaseStructure($oConfig, 'upgrade'); - $oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'AfterDatabaseCreation'); + $oRuntimeEnv->CallInstallerHandlers($aAvailableModules, 'AfterDatabaseCreation'); $oRuntimeEnv->UpdatePredefinedObjects(); - $oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'AfterDatabaseSetup'); - $oRuntimeEnv->LoadData($aAvailableModules, $aSelectedModules, false /* no sample data*/); - $oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'AfterDataLoad'); + $oRuntimeEnv->CallInstallerHandlers($aAvailableModules, 'AfterDatabaseSetup'); + $oRuntimeEnv->LoadData($aAvailableModules, false /* no sample data*/); + $oRuntimeEnv->CallInstallerHandlers($aAvailableModules, 'AfterDataLoad'); $sDataModelVersion = $oRuntimeEnv->GetCurrentDataModelVersion(); $oExtensionsMap = new iTopExtensionsMap(); // Default choices = as before @@ -187,7 +179,7 @@ final class CoreUpdater $oRuntimeEnv->RecordInstallation( $oConfig, $sDataModelVersion, - $aSelectedModules, + array_keys($aAvailableModules), $aSelectedExtensionCodes, 'Done by the iTop Core Updater' ); diff --git a/datamodels/2.x/itop-core-update/src/Service/RunTimeEnvironmentCoreUpdater.php b/datamodels/2.x/itop-core-update/src/Service/RunTimeEnvironmentCoreUpdater.php index dd5a6de402..b38a0d682d 100644 --- a/datamodels/2.x/itop-core-update/src/Service/RunTimeEnvironmentCoreUpdater.php +++ b/datamodels/2.x/itop-core-update/src/Service/RunTimeEnvironmentCoreUpdater.php @@ -11,7 +11,6 @@ require_once(APPROOT."setup/runtimeenv.class.inc.php"); use Config; use Exception; -use ModelFactory; use RunTimeEnvironment; use SetupUtils; @@ -25,33 +24,31 @@ class RunTimeEnvironmentCoreUpdater extends RunTimeEnvironment * * @throws \Exception */ - public function __construct($sEnvironment = 'production', $bAutoCommit = true) + public function __construct($sEnvironment = ITOP_DEFAULT_ENV, $bAutoCommit = true) { parent::__construct($sEnvironment, $bAutoCommit); - if ($sEnvironment != $this->sTargetEnv) { - if (is_dir(APPROOT.'/env-'.$this->sTargetEnv)) { - SetupUtils::rrmdir(APPROOT.'/env-'.$this->sTargetEnv); + if ($sEnvironment != $this->sBuildEnv) { + if (is_dir(APPROOT.'/env-'.$this->sBuildEnv)) { + SetupUtils::rrmdir(APPROOT.'/env-'.$this->sBuildEnv); } - if (is_dir(APPROOT.'/data/'.$this->sTargetEnv.'-modules')) { - SetupUtils::rrmdir(APPROOT.'/data/'.$this->sTargetEnv.'-modules'); + if (is_dir(APPROOT.'/data/'.$this->sBuildEnv.'-modules')) { + SetupUtils::rrmdir(APPROOT.'/data/'.$this->sBuildEnv.'-modules'); } - SetupUtils::copydir(APPROOT.'/data/'.$sEnvironment.'-modules', APPROOT.'/data/'.$this->sTargetEnv.'-modules'); + SetupUtils::copydir(APPROOT.'/data/'.$sEnvironment.'-modules', APPROOT.'/data/'.$this->sBuildEnv.'-modules'); } } /** - * @param $sTargetEnv + * @param $sBuildEnv * * @throws \Exception */ - public function CheckDirectories($sTargetEnv) + public function CheckDirectories($sBuildEnv) { - $sTargetDir = APPROOT.'env-'.$sTargetEnv; - $sBuildDir = $sTargetDir.'-build'; - - self::CheckDirectory($sTargetDir); - self::CheckDirectory($sBuildDir); + $sCurrentEnvDir = APPROOT.'env-'.$sBuildEnv; + self::CheckDirectory($sCurrentEnvDir); + self::CheckDirectory($sCurrentEnvDir.'-build'); } /** @@ -83,12 +80,12 @@ class RunTimeEnvironmentCoreUpdater extends RunTimeEnvironment { // Clone the default 'production' config file // - $oConfig = clone($this->GetConfig('production')); + $oConfig = clone($this->GetConfig(ITOP_DEFAULT_ENV)); - $oConfig->UpdateIncludes('env-'.$this->sTargetEnv); + $oConfig->UpdateIncludes('env-'.$this->sBuildEnv); if (is_null($sEnvironmentLabel)) { - $sEnvironmentLabel = $this->sTargetEnv; + $sEnvironmentLabel = $this->sBuildEnv; } $oConfig->Set('app_env_label', $sEnvironmentLabel, 'application updater'); @@ -104,7 +101,7 @@ class RunTimeEnvironmentCoreUpdater extends RunTimeEnvironment protected function GetConfig($sEnvironment = null) { if (is_null($sEnvironment)) { - $sEnvironment = $this->sTargetEnv; + $sEnvironment = $this->sBuildEnv; } $sFile = APPCONF.$sEnvironment.'/'.ITOP_CONFIG_FILE; if (file_exists($sFile)) { @@ -115,37 +112,4 @@ class RunTimeEnvironmentCoreUpdater extends RunTimeEnvironment } throw new Exception('No configuration file available'); } - - protected function GetMFModulesToCompile($sSourceEnv, $sSourceDir) - { - $aRet = parent::GetMFModulesToCompile($sSourceEnv, $sSourceDir); - - // Add new mandatory modules from datamodel 2.x only - $sSourceDirFull = APPROOT.$sSourceDir; - if (!is_dir($sSourceDirFull)) { - throw new Exception("The source directory '$sSourceDirFull' does not exist (or could not be read)"); - } - $aDirsToCompile = [$sSourceDirFull]; - - $oFactory = new ModelFactory($aDirsToCompile); - $aModules = $oFactory->FindModules(); - $aAvailableModules = []; - /** @var \MFModule $oModule */ - foreach ($aModules as $oModule) { - $aAvailableModules[$oModule->GetName()] = $oModule; - } - // TODO check the auto-selected modules here - foreach ($this->oExtensionsMap->GetAllExtensions() as $oExtension) { - if ($oExtension->bMarkedAsChosen) { - foreach ($oExtension->aModules as $sModuleName) { - if (!isset($aRet[$sModuleName]) && isset($aAvailableModules[$sModuleName])) { - $aRet[$sModuleName] = $aAvailableModules[$sModuleName]; - } - } - } - } - - return $aRet; - } - } diff --git a/datamodels/2.x/itop-core-update/templates/SelectUpdateFile.html.twig b/datamodels/2.x/itop-core-update/templates/SelectUpdateFile.html.twig index 33d68114e3..389641e683 100644 --- a/datamodels/2.x/itop-core-update/templates/SelectUpdateFile.html.twig +++ b/datamodels/2.x/itop-core-update/templates/SelectUpdateFile.html.twig @@ -65,11 +65,11 @@ {% UIFileSelect Standard {sName: 'file', sId: 'file','AddCSSClass':'ibo-is-hidden'} %} {% UIAlert ForWarning {'sId':'dobackup-warning', 'IsHidden':true} %} - {{ 'iTopUpdate:UI:DoBackup:Warning'|dict_s }} + {{ 'iTopUpdate:UI:Backup:Warning'|dict_s }} {% EndUIAlert %} {% UIContentBlock Standard {'aContainerClasses':['ibo-font-ral-nor-150']} %} - {% UIInput Standard {'sType':'checkbox', 'sId':'doBackup', 'sName':'doBackup', 'sValue':'1', 'IsChecked':true, 'CSSClasses':['ibo-input-checkbox', 'ibo-input--label-left'], 'Label':'iTopUpdate:UI:DoBackup:Label'|dict_s} %} + {% UIInput Standard {'sType':'checkbox', 'sId':'doBackup', 'sName':'doBackup', 'sValue':'1', 'IsChecked':true, 'CSSClasses':['ibo-input-checkbox', 'ibo-input--label-left'], 'Label':'iTopUpdate:UI:Backup:Label'|dict_s} %} {% EndUIContentBlock %} {% UIContentBlock Standard {'aContainerClasses':['ibo-font-ral-nor-150']} %} diff --git a/datamodels/2.x/itop-faq-light/module.itop-faq-light.php b/datamodels/2.x/itop-faq-light/module.itop-faq-light.php index a342b2e4e1..92173cb608 100755 --- a/datamodels/2.x/itop-faq-light/module.itop-faq-light.php +++ b/datamodels/2.x/itop-faq-light/module.itop-faq-light.php @@ -21,6 +21,7 @@ SetupWebPage::AddModule( // Components // 'datamodel' => [ + 'model.itop-faq-light.php', ], 'data.struct' => [ //'data.struct.itop-knownerror-mgmt.xml', diff --git a/datamodels/2.x/itop-hub-connector/ajax.php b/datamodels/2.x/itop-hub-connector/ajax.php index 05bdf20a6b..23559f9e54 100644 --- a/datamodels/2.x/itop-hub-connector/ajax.php +++ b/datamodels/2.x/itop-hub-connector/ajax.php @@ -24,129 +24,13 @@ * @license http://opensource.org/licenses/AGPL-3.0 */ -use Combodo\iTop\Application\WebPage\JsonPage; +use Combodo\iTop\HubConnector\Controller\HubController; require_once(APPROOT.'application/utils.inc.php'); require_once(APPROOT.'core/log.class.inc.php'); IssueLog::Enable(APPROOT.'log/error.log'); -require_once(APPROOT.'setup/runtimeenv.class.inc.php'); -require_once(APPROOT.'setup/backup.class.inc.php'); -require_once(APPROOT.'core/mutex.class.inc.php'); -require_once(APPROOT.'core/dict.class.inc.php'); -require_once(APPROOT.'setup/xmldataloader.class.inc.php'); -require_once(__DIR__.'/hubruntimeenvironment.class.inc.php'); - -/** - * Overload of DBBackup to handle logging - */ -class DBBackupWithErrorReporting extends DBBackup -{ - protected $aInfos = []; - - protected $aErrors = []; - - protected function LogInfo($sMsg) - { - $aInfos[] = $sMsg; - } - - protected function LogError($sMsg) - { - IssueLog::Error($sMsg); - $aErrors[] = $sMsg; - } - - public function GetInfos() - { - return $this->aInfos; - } - - public function GetErrors() - { - return $this->aErrors; - } -} - -/** - * - * @param string $sTargetFile - * @throws Exception - * @return DBBackupWithErrorReporting - */ -function DoBackup($sTargetFile) -{ - // Make sure the target directory exists - $sBackupDir = dirname($sTargetFile); - SetupUtils::builddir($sBackupDir); - - $oBackup = new DBBackupWithErrorReporting(); - $oBackup->SetMySQLBinDir(MetaModel::GetConfig()->GetModuleSetting('itop-backup', 'mysql_bindir', '')); - $sSourceConfigFile = APPCONF.utils::GetCurrentEnvironment().'/'.ITOP_CONFIG_FILE; - - $oMutex = new iTopMutex('backup.'.utils::GetCurrentEnvironment()); - $oMutex->Lock(); - try { - $oBackup->CreateCompressedBackup($sTargetFile, $sSourceConfigFile); - } catch (Exception $e) { - $oMutex->Unlock(); - throw $e; - } - $oMutex->Unlock(); - return $oBackup; -} - -/** - * Outputs the status of the current ajax execution (as a JSON structure) - * - * @param string $sMessage - * @param bool $bSuccess - * @param number $iErrorCode - * @param array $aMoreFields - * Extra fields to pass to the caller, if needed - */ -function ReportStatus($sMessage, $bSuccess, $iErrorCode = 0, $aMoreFields = []) -{ - // Do not use AjaxPage during setup phases, because it uses InterfaceDiscovery in Twig compilation - $oPage = new JsonPage(); - $aResult = [ - 'code' => $iErrorCode, - 'message' => $sMessage, - 'fields' => $aMoreFields, - ]; - $oPage->SetData($aResult); - $oPage->SetOutputDataOnly(true); - $oPage->output(); -} - -/** - * Helper to output the status of a successful execution - * - * @param string $sMessage - * @param array $aMoreFields - * Extra fields to pass to the caller, if needed - */ -function ReportSuccess($sMessage, $aMoreFields = []) -{ - ReportStatus($sMessage, true, 0, $aMoreFields); -} - -/** - * Helper to output the status of a failed execution - * - * @param string $sMessage - * @param number $iErrorCode - * @param array $aMoreFields - * Extra fields to pass to the caller, if needed - */ -function ReportError($sMessage, $iErrorCode, $aMoreFields = []) -{ - if ($iErrorCode == 0) { - // 0 means no error, so change it if no meaningful error code is supplied - $iErrorCode = -1; - } - ReportStatus($sMessage, false, $iErrorCode, $aMoreFields); -} +require_once(__DIR__.'/src/Controller/HubController.php'); try { SetupUtils::ExitMaintenanceMode(false); // Reset maintenance mode in case of problem @@ -183,7 +67,7 @@ try { foreach ($aChecks as $oCheckResult) { if ($oCheckResult->iSeverity == CheckResult::ERROR) { $bFailed = true; - ReportError($oCheckResult->sLabel, -2); + HubController::GetInstance()->ReportError($oCheckResult->sLabel, -2); } } if (!$bFailed) { @@ -191,182 +75,27 @@ try { $fFreeSpace = SetupUtils::CheckDiskSpace($sDBBackupPath); if ($fFreeSpace !== false) { $sMessage = Dict::Format('iTopHub:BackupFreeDiskSpaceIn', SetupUtils::HumanReadableSize($fFreeSpace), dirname($sDBBackupPath)); - ReportSuccess($sMessage); + HubController::GetInstance()->ReportSuccess($sMessage); } else { - ReportError(Dict::S('iTopHub:FailedToCheckFreeDiskSpace'), -1); + HubController::GetInstance()->ReportError(Dict::S('iTopHub:FailedToCheckFreeDiskSpace'), -1); } } break; case 'do_backup': - require_once(APPROOT.'/application/startup.inc.php'); - require_once(APPROOT.'/application/loginwebpage.class.inc.php'); - LoginWebPage::DoLogin(true); // Check user rights and prompt if needed (must be admin) - - try { - if (MetaModel::GetConfig()->Get('demo_mode')) { - throw new Exception('Sorry the installation of extensions is not allowed in demo mode'); - } - SetupLog::Info('Backup starts...'); - set_time_limit(0); - $sBackupPath = APPROOT.'/data/backups/manual/backup-'; - $iSuffix = 1; - $sSuffix = ''; - // Generate a unique name... - do { - $sBackupFile = $sBackupPath.date('Y-m-d-His').$sSuffix; - $sSuffix = '-'.$iSuffix; - $iSuffix++ ; - } while (file_exists($sBackupFile)); - - $oBackup = DoBackup($sBackupFile); - $aErrors = $oBackup->GetErrors(); - if (count($aErrors) > 0) { - SetupLog::Error('Backup failed.'); - SetupLog::Error(implode("\n", $aErrors)); - ReportError(Dict::S('iTopHub:BackupFailed'), -1, $aErrors); - } else { - SetupLog::Info('Backup successfully completed.'); - ReportSuccess(Dict::S('iTopHub:BackupOk')); - } - } catch (Exception $e) { - SetupLog::Error($e->getMessage()); - ReportError($e->getMessage(), $e->getCode()); - } + HubController::GetInstance()->LaunchBackup(); break; case 'compile': - SetupLog::Info('Deployment starts...'); - $sAuthent = utils::ReadParam('authent', '', false, 'raw_data'); - if (!file_exists(utils::GetDataPath().'hub/compile_authent') || $sAuthent !== file_get_contents(utils::GetDataPath().'hub/compile_authent')) { - throw new SecurityException(Dict::S('iTopHub:FailAuthent')); - } - // First step: prepare the datamodel, if it fails, roll-back - $aSelectedExtensionCodes = utils::ReadParam('extension_codes', [], false, utils::ENUM_SANITIZATION_FILTER_MODULE_CODE); - $aSelectedExtensionDirs = utils::ReadParam('extension_dirs', [], false, utils::ENUM_SANITIZATION_FILTER_MODULE_CODE); - - $oRuntimeEnv = new HubRunTimeEnvironment('production', false); // use a temp environment: production-build - $oRuntimeEnv->MoveSelectedExtensions(APPROOT.'/data/downloaded-extensions/', $aSelectedExtensionDirs); - - $oConfig = new Config(APPCONF.'production/'.ITOP_CONFIG_FILE); - if ($oConfig->Get('demo_mode')) { - throw new Exception('Sorry the installation of extensions is not allowed in demo mode'); - } - - $aSelectModules = $oRuntimeEnv->CompileFrom('production', false); // WARNING symlinks does not seem to be compatible with manual Commit - - $oRuntimeEnv->UpdateIncludes($oConfig); - - $oRuntimeEnv->InitDataModel($oConfig, true /* model only */); - - // Safety check: check the inter dependencies, will throw an exception in case of inconsistency - $oRuntimeEnv->AnalyzeInstallation($oConfig, $oRuntimeEnv->GetBuildDir(), true); - - $oRuntimeEnv->CheckMetaModel(); // Will throw an exception if a problem is detected - - // Everything seems Ok so far, commit in env-production! - $oRuntimeEnv->WriteConfigFileSafe($oConfig); - $oRuntimeEnv->Commit(); - - // Report the success in a way that will be detected by the ajax caller - SetupLog::Info('Compilation completed...'); - ReportSuccess('Ok'); // No access to Dict::S here + HubController::GetInstance()->LaunchCompile(); break; case 'move_to_production': - // Second step: update the schema and the data - // Everything happening below is based on env-production - $oRuntimeEnv = new RunTimeEnvironment('production', true); - - try { - $sAuthent = utils::ReadParam('authent', '', false, 'raw_data'); - if (!file_exists(utils::GetDataPath().'hub/compile_authent') || $sAuthent !== file_get_contents(utils::GetDataPath().'hub/compile_authent')) { - throw new SecurityException(Dict::S('iTopHub:FailAuthent')); - } - } catch (Exception $e) { - if (file_exists(APPROOT.'data/hub/compile_authent')) { - unlink(APPROOT.'data/hub/compile_authent'); - } - // Note: at this point, the dictionnary is not necessarily loaded - SetupLog::Error(get_class($e).': '.Dict::S('iTopHub:ConfigurationSafelyReverted')."\n".$e->getMessage()); - SetupLog::Error('Debug trace: '.$e->getTraceAsString()); - ReportError($e->getMessage(), $e->getCode()); - break; - } - - try { - SetupLog::Info('Move to production starts...'); - - unlink(utils::GetDataPath().'hub/compile_authent'); - // Load the "production" config file to clone & update it - $oConfig = new Config(APPCONF.'production/'.ITOP_CONFIG_FILE); - SetupUtils::EnterReadOnlyMode($oConfig); - - $oRuntimeEnv->InitDataModel($oConfig, true /* model only */); - - $aAvailableModules = $oRuntimeEnv->AnalyzeInstallation($oConfig, $oRuntimeEnv->GetBuildDir(), true); - - $aSelectedModules = []; - foreach ($aAvailableModules as $sModuleId => $aModule) { - if (($sModuleId == ROOT_MODULE) || ($sModuleId == DATAMODEL_MODULE)) { - continue; - } else { - $aSelectedModules[] = $sModuleId; - } - } - - $oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'BeforeDatabaseCreation'); - - $oRuntimeEnv->CreateDatabaseStructure($oConfig, 'upgrade'); - - $oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'AfterDatabaseCreation'); - - $oRuntimeEnv->UpdatePredefinedObjects(); - - $oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'AfterDatabaseSetup'); - - $oRuntimeEnv->LoadData($aAvailableModules, $aSelectedModules, false /* no sample data*/); - - $oRuntimeEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'AfterDataLoad'); - - // Record the installation so that the "about box" knows about the installed modules - $sDataModelVersion = $oRuntimeEnv->GetCurrentDataModelVersion(); - - $oExtensionsMap = new iTopExtensionsMap(); - - // Default choices = as before - $oExtensionsMap->LoadChoicesFromDatabase($oConfig); - foreach ($oExtensionsMap->GetAllExtensions() as $oExtension) { - // Plus all "remote" extensions - if ($oExtension->sSource == iTopExtension::SOURCE_REMOTE) { - $oExtensionsMap->MarkAsChosen($oExtension->sCode); - } - } - $aSelectedExtensionCodes = []; - foreach ($oExtensionsMap->GetChoices() as $oExtension) { - $aSelectedExtensionCodes[] = $oExtension->sCode; - } - $aSelectedExtensions = $oExtensionsMap->GetChoices(); - $oRuntimeEnv->RecordInstallation($oConfig, $sDataModelVersion, $aSelectedModules, $aSelectedExtensionCodes, 'Done by the iTop Hub Connector'); - - // Report the success in a way that will be detected by the ajax caller - SetupLog::Info('Deployment successfully completed.'); - ReportSuccess(Dict::S('iTopHub:CompiledOK')); - } catch (Exception $e) { - if (file_exists(utils::GetDataPath().'hub/compile_authent')) { - unlink(utils::GetDataPath().'hub/compile_authent'); - } - // Note: at this point, the dictionnary is not necessarily loaded - SetupLog::Error(get_class($e).': '.Dict::S('iTopHub:ConfigurationSafelyReverted')."\n".$e->getMessage()); - SetupLog::Error('Debug trace: '.$e->getTraceAsString()); - ReportError($e->getMessage(), $e->getCode()); - } finally { - SetupUtils::ExitReadOnlyMode(); - } + HubController::GetInstance()->LaunchDeploy(); break; default: - ReportError("Invalid operation: '$sOperation'", -1); + HubController::GetInstance()->ReportError("Invalid operation: '$sOperation'", -1); } } catch (Exception $e) { SetupLog::Error(get_class($e).': '.Dict::S('iTopHub:ConfigurationSafelyReverted')."\n".$e->getMessage()); @@ -374,5 +103,5 @@ try { utils::PopArchiveMode(); - ReportError($e->getMessage(), $e->getCode()); + HubController::GetInstance()->ReportError($e->getMessage(), $e->getCode()); } diff --git a/datamodels/2.x/itop-hub-connector/land.php b/datamodels/2.x/itop-hub-connector/land.php index d50ac2b3d0..b3553af0af 100644 --- a/datamodels/2.x/itop-hub-connector/land.php +++ b/datamodels/2.x/itop-hub-connector/land.php @@ -20,7 +20,7 @@ function DisplayStatus(WebPage $oPage) if (is_dir($sPath)) { $aExtraDirs[] = $sPath; // Also read the extra downloaded-modules directory } - $oExtensionsMap = new iTopExtensionsMap('production', $aExtraDirs); + $oExtensionsMap = new iTopExtensionsMap(ITOP_DEFAULT_ENV, $aExtraDirs); $oExtensionsMap->LoadChoicesFromDatabase(MetaModel::GetConfig()); foreach ($oExtensionsMap->GetAllExtensions() as $oExtension) { @@ -154,7 +154,7 @@ function DoInstall(WebPage $oPage) if (is_dir($sPath)) { $aExtraDirs[] = $sPath; // Also read the extra downloaded-modules directory } - $oExtensionsMap = new iTopExtensionsMap('production', $aExtraDirs); + $oExtensionsMap = new iTopExtensionsMap(ITOP_DEFAULT_ENV, $aExtraDirs); $oExtensionsMap->LoadChoicesFromDatabase(MetaModel::GetConfig()); foreach ($oExtensionsMap->GetAllExtensions() as $oExtension) { diff --git a/datamodels/2.x/itop-hub-connector/launch.php b/datamodels/2.x/itop-hub-connector/launch.php index 8797cf38f0..1f3e520840 100644 --- a/datamodels/2.x/itop-hub-connector/launch.php +++ b/datamodels/2.x/itop-hub-connector/launch.php @@ -186,9 +186,7 @@ function collect_configuration() // iTop modules $oConfig = MetaModel::GetConfig(); - $sLatestInstallationDate = CMDBSource::QueryToScalar("SELECT max(installed) FROM ".$oConfig->Get('db_subname')."priv_module_install"); - // Get the latest installed modules, without the "root" ones (iTop version and datamodel version) - $aInstalledModules = CMDBSource::QueryToArray("SELECT * FROM ".$oConfig->Get('db_subname')."priv_module_install WHERE installed = '".$sLatestInstallationDate."' AND parent_id != 0"); + $aInstalledModules = ModuleInstallationRepository::GetInstance()->ReadFromDB($oConfig); foreach ($aInstalledModules as $aDBInfo) { $aConfiguration['itop_modules'][$aDBInfo['name']] = $aDBInfo['version']; diff --git a/datamodels/2.x/itop-hub-connector/src/Controller/HubController.php b/datamodels/2.x/itop-hub-connector/src/Controller/HubController.php new file mode 100644 index 0000000000..fdbe2fbc8c --- /dev/null +++ b/datamodels/2.x/itop-hub-connector/src/Controller/HubController.php @@ -0,0 +1,314 @@ +Get('demo_mode')) { + throw new Exception('Sorry the installation of extensions is not allowed in demo mode'); + } + SetupLog::Info('Backup starts...'); + set_time_limit(0); + $sBackupPath = APPROOT.'/data/backups/manual/backup-'; + $iSuffix = 1; + $sSuffix = ''; + // Generate a unique name... + do { + $sBackupFile = $sBackupPath.date('Y-m-d-His').$sSuffix; + $sSuffix = '-'.$iSuffix; + $iSuffix++ ; + } while (file_exists($sBackupFile)); + + $oBackup = $this->DoBackup($sBackupFile); + $aErrors = $oBackup->GetErrors(); + if (count($aErrors) > 0) { + SetupLog::Error('Backup failed.'); + SetupLog::Error(implode("\n", $aErrors)); + $this->ReportError(Dict::S('iTopHub:BackupFailed'), -1, $aErrors); + } else { + SetupLog::Info('Backup successfully completed.'); + $this->ReportSuccess(Dict::S('iTopHub:BackupOk')); + } + } catch (Exception $e) { + SetupLog::Error($e->getMessage()); + $this->ReportError($e->getMessage(), $e->getCode()); + } + } + + /** + * + * @param string $sTargetFile + * @throws Exception + * @return DBBackupWithErrorReporting + */ + public function DoBackup($sTargetFile): DBBackupWithErrorReporting + { + // Make sure the target directory exists + $sBackupDir = dirname($sTargetFile); + SetupUtils::builddir($sBackupDir); + + $oBackup = new DBBackupWithErrorReporting(); + $oBackup->SetMySQLBinDir(MetaModel::GetConfig()->GetModuleSetting('itop-backup', 'mysql_bindir', '')); + $sSourceConfigFile = APPCONF.utils::GetCurrentEnvironment().'/'.ITOP_CONFIG_FILE; + + $oMutex = new iTopMutex('backup.'.utils::GetCurrentEnvironment()); + $oMutex->Lock(); + try { + $oBackup->CreateCompressedBackup($sTargetFile, $sSourceConfigFile); + } catch (Exception $e) { + $oMutex->Unlock(); + throw $e; + } + $oMutex->Unlock(); + return $oBackup; + } + + public function LaunchCompile() + { + SetupLog::Info('Deployment starts...'); + $sAuthent = utils::ReadParam('authent', '', false, 'raw_data'); + if (!file_exists(utils::GetDataPath().'hub/compile_authent') || $sAuthent !== file_get_contents(utils::GetDataPath().'hub/compile_authent')) { + throw new SecurityException(Dict::S('iTopHub:FailAuthent')); + } + // First step: prepare the datamodel, if it fails, roll-back + $aSelectedExtensionDirs = utils::ReadParam('extension_dirs', [], false, utils::ENUM_SANITIZATION_FILTER_MODULE_CODE); + + $oRuntimeEnv = new HubRunTimeEnvironment('production', false); // use a temp environment: production-build + $oRuntimeEnv->MoveSelectedExtensions(APPROOT.'/data/downloaded-extensions/', $aSelectedExtensionDirs); + + $oConfig = new Config(APPCONF.'production/'.ITOP_CONFIG_FILE); + if ($oConfig->Get('demo_mode')) { + throw new Exception('Sorry the installation of extensions is not allowed in demo mode'); + } + + $aSelectModules = $oRuntimeEnv->CompileFrom('production'); // WARNING symlinks does not seem to be compatible with manual Commit + + $oRuntimeEnv->UpdateIncludes($oConfig); + + $oRuntimeEnv->InitDataModel($oConfig, true /* model only */); + + // Safety check: check the inter dependencies, will throw an exception in case of inconsistency + $oRuntimeEnv->AnalyzeInstallation($oConfig, $oRuntimeEnv->GetBuildDir(), true); + + $oRuntimeEnv->CheckMetaModel(); // Will throw an exception if a problem is detected + + // Everything seems Ok so far, commit in env-production! + $oRuntimeEnv->WriteConfigFileSafe($oConfig); + $oRuntimeEnv->Commit(); + + // Report the success in a way that will be detected by the ajax caller + SetupLog::Info('Compilation completed...'); + + $this->ReportSuccess('Ok'); // No access to Dict::S here + } + + public function LaunchDeploy() + { + // Second step: update the schema and the data + // Everything happening below is based on env-production + $oRuntimeEnv = new RunTimeEnvironment('production', true); + + try { + $sAuthent = utils::ReadParam('authent', '', false, 'raw_data'); + if (!file_exists(utils::GetDataPath().'hub/compile_authent') || $sAuthent !== file_get_contents(utils::GetDataPath().'hub/compile_authent')) { + throw new SecurityException(Dict::S('iTopHub:FailAuthent')); + } + } catch (Exception $e) { + if (file_exists(utils::GetDataPath().'hub/compile_authent')) { + unlink(utils::GetDataPath().'hub/compile_authent'); + } + // Note: at this point, the dictionnary is not necessarily loaded + SetupLog::Error(get_class($e).': '.Dict::S('iTopHub:ConfigurationSafelyReverted')."\n".$e->getMessage()); + SetupLog::Error('Debug trace: '.$e->getTraceAsString()); + $this->ReportError($e->getMessage(), $e->getCode()); + return; + } + + try { + SetupLog::Info('Move to production starts...'); + $sAuthent = utils::ReadParam('authent', '', false, 'raw_data'); + if (!file_exists(utils::GetDataPath().'hub/compile_authent') || $sAuthent !== file_get_contents(utils::GetDataPath().'hub/compile_authent')) { + throw new SecurityException(Dict::S('iTopHub:FailAuthent')); + } + unlink(utils::GetDataPath().'hub/compile_authent'); + // Load the "production" config file to clone & update it + $oConfig = new Config(APPCONF.'production/'.ITOP_CONFIG_FILE); + SetupUtils::EnterReadOnlyMode($oConfig); + + $oRuntimeEnv->InitDataModel($oConfig, true /* model only */); + + $aAvailableModules = $oRuntimeEnv->AnalyzeInstallation($oConfig, $oRuntimeEnv->GetBuildDir(), true); + + $oRuntimeEnv->CallInstallerHandlers($aAvailableModules, 'BeforeDatabaseCreation'); + + $oRuntimeEnv->CreateDatabaseStructure($oConfig, 'upgrade'); + + $oRuntimeEnv->CallInstallerHandlers($aAvailableModules, 'AfterDatabaseCreation'); + + $oRuntimeEnv->UpdatePredefinedObjects(); + + $oRuntimeEnv->CallInstallerHandlers($aAvailableModules, 'AfterDatabaseSetup'); + + $oRuntimeEnv->LoadData($aAvailableModules, false /* no sample data*/); + + $oRuntimeEnv->CallInstallerHandlers($aAvailableModules, 'AfterDataLoad'); + + // Record the installation so that the "about box" knows about the installed modules + $sDataModelVersion = $oRuntimeEnv->GetCurrentDataModelVersion(); + + $oExtensionsMap = new iTopExtensionsMap(); + + // Default choices = as before + $oExtensionsMap->LoadChoicesFromDatabase($oConfig); + foreach ($oExtensionsMap->GetAllExtensions() as $oExtension) { + // Plus all "remote" extensions + if ($oExtension->sSource == iTopExtension::SOURCE_REMOTE) { + $oExtensionsMap->MarkAsChosen($oExtension->sCode); + } + } + $aSelectedExtensionCodes = []; + foreach ($oExtensionsMap->GetChoices() as $oExtension) { + $aSelectedExtensionCodes[] = $oExtension->sCode; + } + $aSelectedExtensions = $oExtensionsMap->GetChoices(); + $oRuntimeEnv->RecordInstallation($oConfig, $sDataModelVersion, array_keys($aAvailableModules), $aSelectedExtensionCodes, 'Done by the iTop Hub Connector'); + + // Report the success in a way that will be detected by the ajax caller + SetupLog::Info('Deployment successfully completed.'); + $this->ReportSuccess(Dict::S('iTopHub:CompiledOK')); + } catch (Exception $e) { + if (file_exists(utils::GetDataPath().'hub/compile_authent')) { + unlink(utils::GetDataPath().'hub/compile_authent'); + } + // Note: at this point, the dictionnary is not necessarily loaded + SetupLog::Error(get_class($e).': '.Dict::S('iTopHub:ConfigurationSafelyReverted')."\n".$e->getMessage()); + SetupLog::Error('Debug trace: '.$e->getTraceAsString()); + $this->ReportError($e->getMessage(), $e->getCode()); + } finally { + SetupUtils::ExitReadOnlyMode(); + } + } + + /** + * Outputs the status of the current ajax execution (as a JSON structure) + * + * @param string $sMessage + * @param bool $bSuccess + * @param number $iErrorCode + * @param array $aMoreFields + * Extra fields to pass to the caller, if needed + */ + public function ReportStatus($sMessage, $bSuccess, $iErrorCode = 0, $aMoreFields = []) + { + // Do not use AjaxPage during setup phases, because it uses InterfaceDiscovery in Twig compilation + $this->oLastJsonPage = new JsonPage(); + $this->oLastJsonPage->SetOutputHeaders($this->bOutputHeaders); + $aResult = [ + 'code' => $iErrorCode, + 'message' => $sMessage, + 'fields' => $aMoreFields, + ]; + $this->oLastJsonPage->SetData($aResult); + $this->oLastJsonPage->SetOutputDataOnly(true); + $this->oLastJsonPage->output(); + } + + private ?JsonPage $oLastJsonPage = null; + + public function GetLastJsonPage(): ?JsonPage + { + return $this->oLastJsonPage; + } + + /** + * Helper to output the status of a successful execution + * + * @param string $sMessage + * @param array $aMoreFields + * Extra fields to pass to the caller, if needed + */ + public function ReportSuccess($sMessage, $aMoreFields = []) + { + $this->ReportStatus($sMessage, true, 0, $aMoreFields); + } + + /** + * Helper to output the status of a failed execution + * + * @param string $sMessage + * @param number $iErrorCode + * @param array $aMoreFields + * Extra fields to pass to the caller, if needed + */ + public function ReportError($sMessage, $iErrorCode, $aMoreFields = []) + { + if ($iErrorCode == 0) { + // 0 means no error, so change it if no meaningful error code is supplied + $iErrorCode = -1; + } + $this->ReportStatus($sMessage, false, $iErrorCode, $aMoreFields); + } + + /** + * Dont print headers for testing purpose mainly + * @param bool bOutputHeaders + * + * @return void + */ + public function SetOutputHeaders(bool $bOutputHeaders): void + { + $this->bOutputHeaders = $bOutputHeaders; + } +} diff --git a/datamodels/2.x/itop-hub-connector/src/Model/DBBackupWithErrorReporting.php b/datamodels/2.x/itop-hub-connector/src/Model/DBBackupWithErrorReporting.php new file mode 100644 index 0000000000..39bcabe856 --- /dev/null +++ b/datamodels/2.x/itop-hub-connector/src/Model/DBBackupWithErrorReporting.php @@ -0,0 +1,37 @@ +aInfos[] = $sMsg; + } + + protected function LogError($sMsg) + { + IssueLog::Error($sMsg); + $this->aErrors[] = $sMsg; + } + + public function GetInfos(): array + { + return $this->aInfos; + } + + public function GetErrors(): array + { + return $this->aErrors; + } +} diff --git a/datamodels/2.x/itop-hub-connector/hubruntimeenvironment.class.inc.php b/datamodels/2.x/itop-hub-connector/src/setup/hubruntimeenvironment.class.inc.php similarity index 66% rename from datamodels/2.x/itop-hub-connector/hubruntimeenvironment.class.inc.php rename to datamodels/2.x/itop-hub-connector/src/setup/hubruntimeenvironment.class.inc.php index c5c722cf77..90fa066b9f 100644 --- a/datamodels/2.x/itop-hub-connector/hubruntimeenvironment.class.inc.php +++ b/datamodels/2.x/itop-hub-connector/src/setup/hubruntimeenvironment.class.inc.php @@ -1,9 +1,17 @@ sTargetEnv) { - if (is_dir(APPROOT.'/env-'.$this->sTargetEnv)) { - SetupUtils::rrmdir(APPROOT.'/env-'.$this->sTargetEnv); + if ($sEnvironment != $this->sBuildEnv) { + if (is_dir(APPROOT.'/env-'.$this->sBuildEnv)) { + SetupUtils::rrmdir(APPROOT.'/env-'.$this->sBuildEnv); } - if (is_dir(APPROOT.'/data/'.$this->sTargetEnv.'-modules')) { - SetupUtils::rrmdir(APPROOT.'/data/'.$this->sTargetEnv.'-modules'); + if (is_dir(APPROOT.'/data/'.$this->sBuildEnv.'-modules')) { + SetupUtils::rrmdir(APPROOT.'/data/'.$this->sBuildEnv.'-modules'); } - SetupUtils::copydir(APPROOT.'/data/'.$sEnvironment.'-modules', APPROOT.'/data/'.$this->sTargetEnv.'-modules'); + SetupUtils::copydir(APPROOT.'/data/'.$sEnvironment.'-modules', APPROOT.'/data/'.$this->sBuildEnv.'-modules'); } } /** - * Update the includes for the target environment + * Update the includes for the build environment + * * @param Config $oConfig */ public function UpdateIncludes(Config $oConfig) { - $oConfig->UpdateIncludes('env-'.$this->sTargetEnv); // TargetEnv != FinalEnv + $oConfig->UpdateIncludes('env-'.$this->sBuildEnv); // BuildEnv != FinalEnv } /** - * Move an extension (path to folder of this extension) to the target environment + * Move an extension (path to folder of this extension) to the build environment + * * @param string $sExtensionDirectory The folder of the extension + * * @throws Exception */ public function MoveExtension($sExtensionDirectory) { - if (!is_dir(APPROOT.'/data/'.$this->sTargetEnv.'-modules')) { - if (!mkdir(APPROOT.'/data/'.$this->sTargetEnv.'-modules')) { - throw new Exception("ERROR: failed to create directory:'".(APPROOT.'/data/'.$this->sTargetEnv.'-modules')."'"); + if (!is_dir(APPROOT.'/data/'.$this->sBuildEnv.'-modules')) { + if (!mkdir(APPROOT.'/data/'.$this->sBuildEnv.'-modules')) { + throw new Exception("ERROR: failed to create directory:'".(APPROOT.'/data/'.$this->sBuildEnv.'-modules')."'"); } } - $sDestinationPath = APPROOT.'/data/'.$this->sTargetEnv.'-modules/'; + $sDestinationPath = APPROOT.'/data/'.$this->sBuildEnv.'-modules/'; // Make sure that the destination directory of the extension does not already exist if (is_dir($sDestinationPath.basename($sExtensionDirectory))) { @@ -56,9 +67,11 @@ class HubRunTimeEnvironment extends RunTimeEnvironment } /** - * Move the selected extensions located in the given directory in data/-modules + * Move the selected extensions located in the given directory in data/-modules + * * @param string $sDownloadedExtensionsDir The directory to scan * @param string[] $aSelectedExtensionDirs The list of folders to move + * * @throws Exception */ public function MoveSelectedExtensions($sDownloadedExtensionsDir, $aSelectedExtensionDirs) diff --git a/dictionaries/ui/layouts/extensions-details/cs.dictionary.itop.extensions-details.php b/dictionaries/ui/layouts/extensions-details/cs.dictionary.itop.extensions-details.php new file mode 100644 index 0000000000..2f38ac0a26 --- /dev/null +++ b/dictionaries/ui/layouts/extensions-details/cs.dictionary.itop.extensions-details.php @@ -0,0 +1,24 @@ + 'installed~~', + 'UI:Layout:ExtensionsDetails:BadgeToBeInstalled' => 'to be installed~~', + 'UI:Layout:ExtensionsDetails:BadgeNotInstalled' => 'not installed~~', + 'UI:Layout:ExtensionsDetails:BadgeToBeUninstalled' => 'to be uninstalled~~', + 'UI:Layout:ExtensionsDetails:BadgeNotUninstallable' => 'cannot be uninstalled~~', + 'UI:Layout:ExtensionsDetails:BadgeMissingFromDisk' => 'missing from disk~~', + 'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~', + 'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~', + 'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~', + 'UI:Layout:ExtensionsDetails:MoreActions' => 'Show more actions~~', +]); diff --git a/dictionaries/ui/layouts/extensions-details/da.dictionary.itop.extensions-details.php b/dictionaries/ui/layouts/extensions-details/da.dictionary.itop.extensions-details.php new file mode 100644 index 0000000000..ad743ccc36 --- /dev/null +++ b/dictionaries/ui/layouts/extensions-details/da.dictionary.itop.extensions-details.php @@ -0,0 +1,24 @@ + 'installed~~', + 'UI:Layout:ExtensionsDetails:BadgeToBeInstalled' => 'to be installed~~', + 'UI:Layout:ExtensionsDetails:BadgeNotInstalled' => 'not installed~~', + 'UI:Layout:ExtensionsDetails:BadgeToBeUninstalled' => 'to be uninstalled~~', + 'UI:Layout:ExtensionsDetails:BadgeNotUninstallable' => 'cannot be uninstalled~~', + 'UI:Layout:ExtensionsDetails:BadgeMissingFromDisk' => 'missing from disk~~', + 'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~', + 'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~', + 'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~', + 'UI:Layout:ExtensionsDetails:MoreActions' => 'Show more actions~~', +]); diff --git a/dictionaries/ui/layouts/extensions-details/de.dictionary.itop.extensions-details.php b/dictionaries/ui/layouts/extensions-details/de.dictionary.itop.extensions-details.php new file mode 100644 index 0000000000..505ce5e34e --- /dev/null +++ b/dictionaries/ui/layouts/extensions-details/de.dictionary.itop.extensions-details.php @@ -0,0 +1,24 @@ + 'installed~~', + 'UI:Layout:ExtensionsDetails:BadgeToBeInstalled' => 'to be installed~~', + 'UI:Layout:ExtensionsDetails:BadgeNotInstalled' => 'not installed~~', + 'UI:Layout:ExtensionsDetails:BadgeToBeUninstalled' => 'to be uninstalled~~', + 'UI:Layout:ExtensionsDetails:BadgeNotUninstallable' => 'cannot be uninstalled~~', + 'UI:Layout:ExtensionsDetails:BadgeMissingFromDisk' => 'missing from disk~~', + 'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~', + 'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~', + 'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~', + 'UI:Layout:ExtensionsDetails:MoreActions' => 'Show more actions~~', +]); diff --git a/dictionaries/ui/layouts/extensions-details/en.dictionary.itop.extensions-details.php b/dictionaries/ui/layouts/extensions-details/en.dictionary.itop.extensions-details.php new file mode 100644 index 0000000000..b8d1415ced --- /dev/null +++ b/dictionaries/ui/layouts/extensions-details/en.dictionary.itop.extensions-details.php @@ -0,0 +1,22 @@ + 'installed', + 'UI:Layout:ExtensionsDetails:BadgeToBeInstalled' => 'to be installed', + 'UI:Layout:ExtensionsDetails:BadgeNotInstalled' => 'not installed', + 'UI:Layout:ExtensionsDetails:BadgeToBeUninstalled' => 'to be uninstalled', + 'UI:Layout:ExtensionsDetails:BadgeNotUninstallable' => 'cannot be uninstalled', + 'UI:Layout:ExtensionsDetails:BadgeMissingFromDisk' => 'missing from disk', + 'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s', + 'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations', + 'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall', + 'UI:Layout:ExtensionsDetails:MoreActions' => 'Show more actions', +]); diff --git a/dictionaries/ui/layouts/extensions-details/es_cr.dictionary.itop.extensions-details.php b/dictionaries/ui/layouts/extensions-details/es_cr.dictionary.itop.extensions-details.php new file mode 100644 index 0000000000..ae18bb850c --- /dev/null +++ b/dictionaries/ui/layouts/extensions-details/es_cr.dictionary.itop.extensions-details.php @@ -0,0 +1,24 @@ + 'installed~~', + 'UI:Layout:ExtensionsDetails:BadgeToBeInstalled' => 'to be installed~~', + 'UI:Layout:ExtensionsDetails:BadgeNotInstalled' => 'not installed~~', + 'UI:Layout:ExtensionsDetails:BadgeToBeUninstalled' => 'to be uninstalled~~', + 'UI:Layout:ExtensionsDetails:BadgeNotUninstallable' => 'cannot be uninstalled~~', + 'UI:Layout:ExtensionsDetails:BadgeMissingFromDisk' => 'missing from disk~~', + 'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~', + 'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~', + 'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~', + 'UI:Layout:ExtensionsDetails:MoreActions' => 'Show more actions~~', +]); diff --git a/dictionaries/ui/layouts/extensions-details/fr.dictionary.itop.extensions-details.php b/dictionaries/ui/layouts/extensions-details/fr.dictionary.itop.extensions-details.php new file mode 100644 index 0000000000..5114c91c77 --- /dev/null +++ b/dictionaries/ui/layouts/extensions-details/fr.dictionary.itop.extensions-details.php @@ -0,0 +1,24 @@ + 'installé', + 'UI:Layout:ExtensionsDetails:BadgeToBeInstalled' => 'va être installé', + 'UI:Layout:ExtensionsDetails:BadgeNotInstalled' => 'pas installé', + 'UI:Layout:ExtensionsDetails:BadgeToBeUninstalled' => 'va être désinstallé', + 'UI:Layout:ExtensionsDetails:BadgeNotUninstallable' => 'non désinstallable', + 'UI:Layout:ExtensionsDetails:BadgeMissingFromDisk' => 'supprimé du disque', + 'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'À propos de %1$s', + 'UI:Layout:ExtensionsDetails:MenuAbout' => 'Plus d\'informations', + 'UI:Layout:ExtensionsDetails:MenuForce' => 'Forcer la désinstallation', + 'UI:Layout:ExtensionsDetails:MoreActions' => 'Plus d\'actions', +]); diff --git a/dictionaries/ui/layouts/extensions-details/hu.dictionary.itop.extensions-details.php b/dictionaries/ui/layouts/extensions-details/hu.dictionary.itop.extensions-details.php new file mode 100644 index 0000000000..cded3a4641 --- /dev/null +++ b/dictionaries/ui/layouts/extensions-details/hu.dictionary.itop.extensions-details.php @@ -0,0 +1,24 @@ + 'installed~~', + 'UI:Layout:ExtensionsDetails:BadgeToBeInstalled' => 'to be installed~~', + 'UI:Layout:ExtensionsDetails:BadgeNotInstalled' => 'not installed~~', + 'UI:Layout:ExtensionsDetails:BadgeToBeUninstalled' => 'to be uninstalled~~', + 'UI:Layout:ExtensionsDetails:BadgeNotUninstallable' => 'cannot be uninstalled~~', + 'UI:Layout:ExtensionsDetails:BadgeMissingFromDisk' => 'missing from disk~~', + 'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~', + 'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~', + 'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~', + 'UI:Layout:ExtensionsDetails:MoreActions' => 'Show more actions~~', +]); diff --git a/dictionaries/ui/layouts/extensions-details/it.dictionary.itop.extensions-details.php b/dictionaries/ui/layouts/extensions-details/it.dictionary.itop.extensions-details.php new file mode 100644 index 0000000000..424a0b13f9 --- /dev/null +++ b/dictionaries/ui/layouts/extensions-details/it.dictionary.itop.extensions-details.php @@ -0,0 +1,24 @@ + 'installed~~', + 'UI:Layout:ExtensionsDetails:BadgeToBeInstalled' => 'to be installed~~', + 'UI:Layout:ExtensionsDetails:BadgeNotInstalled' => 'not installed~~', + 'UI:Layout:ExtensionsDetails:BadgeToBeUninstalled' => 'to be uninstalled~~', + 'UI:Layout:ExtensionsDetails:BadgeNotUninstallable' => 'cannot be uninstalled~~', + 'UI:Layout:ExtensionsDetails:BadgeMissingFromDisk' => 'missing from disk~~', + 'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~', + 'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~', + 'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~', + 'UI:Layout:ExtensionsDetails:MoreActions' => 'Show more actions~~', +]); diff --git a/dictionaries/ui/layouts/extensions-details/ja.dictionary.itop.extensions-details.php b/dictionaries/ui/layouts/extensions-details/ja.dictionary.itop.extensions-details.php new file mode 100644 index 0000000000..96703e5832 --- /dev/null +++ b/dictionaries/ui/layouts/extensions-details/ja.dictionary.itop.extensions-details.php @@ -0,0 +1,24 @@ + 'installed~~', + 'UI:Layout:ExtensionsDetails:BadgeToBeInstalled' => 'to be installed~~', + 'UI:Layout:ExtensionsDetails:BadgeNotInstalled' => 'not installed~~', + 'UI:Layout:ExtensionsDetails:BadgeToBeUninstalled' => 'to be uninstalled~~', + 'UI:Layout:ExtensionsDetails:BadgeNotUninstallable' => 'cannot be uninstalled~~', + 'UI:Layout:ExtensionsDetails:BadgeMissingFromDisk' => 'missing from disk~~', + 'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~', + 'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~', + 'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~', + 'UI:Layout:ExtensionsDetails:MoreActions' => 'Show more actions~~', +]); diff --git a/dictionaries/ui/layouts/extensions-details/nl.dictionary.itop.extensions-details.php b/dictionaries/ui/layouts/extensions-details/nl.dictionary.itop.extensions-details.php new file mode 100644 index 0000000000..1774a4dca1 --- /dev/null +++ b/dictionaries/ui/layouts/extensions-details/nl.dictionary.itop.extensions-details.php @@ -0,0 +1,24 @@ + 'installed~~', + 'UI:Layout:ExtensionsDetails:BadgeToBeInstalled' => 'to be installed~~', + 'UI:Layout:ExtensionsDetails:BadgeNotInstalled' => 'not installed~~', + 'UI:Layout:ExtensionsDetails:BadgeToBeUninstalled' => 'to be uninstalled~~', + 'UI:Layout:ExtensionsDetails:BadgeNotUninstallable' => 'cannot be uninstalled~~', + 'UI:Layout:ExtensionsDetails:BadgeMissingFromDisk' => 'missing from disk~~', + 'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~', + 'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~', + 'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~', + 'UI:Layout:ExtensionsDetails:MoreActions' => 'Show more actions~~', +]); diff --git a/dictionaries/ui/layouts/extensions-details/pl.dictionary.itop.extensions-details.php b/dictionaries/ui/layouts/extensions-details/pl.dictionary.itop.extensions-details.php new file mode 100644 index 0000000000..48628bd08e --- /dev/null +++ b/dictionaries/ui/layouts/extensions-details/pl.dictionary.itop.extensions-details.php @@ -0,0 +1,24 @@ + 'installed~~', + 'UI:Layout:ExtensionsDetails:BadgeToBeInstalled' => 'to be installed~~', + 'UI:Layout:ExtensionsDetails:BadgeNotInstalled' => 'not installed~~', + 'UI:Layout:ExtensionsDetails:BadgeToBeUninstalled' => 'to be uninstalled~~', + 'UI:Layout:ExtensionsDetails:BadgeNotUninstallable' => 'cannot be uninstalled~~', + 'UI:Layout:ExtensionsDetails:BadgeMissingFromDisk' => 'missing from disk~~', + 'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~', + 'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~', + 'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~', + 'UI:Layout:ExtensionsDetails:MoreActions' => 'Show more actions~~', +]); diff --git a/dictionaries/ui/layouts/extensions-details/pt_br.dictionary.itop.extensions-details.php b/dictionaries/ui/layouts/extensions-details/pt_br.dictionary.itop.extensions-details.php new file mode 100644 index 0000000000..f469ddfdfc --- /dev/null +++ b/dictionaries/ui/layouts/extensions-details/pt_br.dictionary.itop.extensions-details.php @@ -0,0 +1,24 @@ + 'installed~~', + 'UI:Layout:ExtensionsDetails:BadgeToBeInstalled' => 'to be installed~~', + 'UI:Layout:ExtensionsDetails:BadgeNotInstalled' => 'not installed~~', + 'UI:Layout:ExtensionsDetails:BadgeToBeUninstalled' => 'to be uninstalled~~', + 'UI:Layout:ExtensionsDetails:BadgeNotUninstallable' => 'cannot be uninstalled~~', + 'UI:Layout:ExtensionsDetails:BadgeMissingFromDisk' => 'missing from disk~~', + 'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~', + 'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~', + 'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~', + 'UI:Layout:ExtensionsDetails:MoreActions' => 'Show more actions~~', +]); diff --git a/dictionaries/ui/layouts/extensions-details/ru.dictionary.itop.extensions-details.php b/dictionaries/ui/layouts/extensions-details/ru.dictionary.itop.extensions-details.php new file mode 100644 index 0000000000..9b5967a04d --- /dev/null +++ b/dictionaries/ui/layouts/extensions-details/ru.dictionary.itop.extensions-details.php @@ -0,0 +1,24 @@ + 'installed~~', + 'UI:Layout:ExtensionsDetails:BadgeToBeInstalled' => 'to be installed~~', + 'UI:Layout:ExtensionsDetails:BadgeNotInstalled' => 'not installed~~', + 'UI:Layout:ExtensionsDetails:BadgeToBeUninstalled' => 'to be uninstalled~~', + 'UI:Layout:ExtensionsDetails:BadgeNotUninstallable' => 'cannot be uninstalled~~', + 'UI:Layout:ExtensionsDetails:BadgeMissingFromDisk' => 'missing from disk~~', + 'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~', + 'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~', + 'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~', + 'UI:Layout:ExtensionsDetails:MoreActions' => 'Show more actions~~', +]); diff --git a/dictionaries/ui/layouts/extensions-details/sk.dictionary.itop.extensions-details.php b/dictionaries/ui/layouts/extensions-details/sk.dictionary.itop.extensions-details.php new file mode 100644 index 0000000000..3aab38ee98 --- /dev/null +++ b/dictionaries/ui/layouts/extensions-details/sk.dictionary.itop.extensions-details.php @@ -0,0 +1,24 @@ + 'installed~~', + 'UI:Layout:ExtensionsDetails:BadgeToBeInstalled' => 'to be installed~~', + 'UI:Layout:ExtensionsDetails:BadgeNotInstalled' => 'not installed~~', + 'UI:Layout:ExtensionsDetails:BadgeToBeUninstalled' => 'to be uninstalled~~', + 'UI:Layout:ExtensionsDetails:BadgeNotUninstallable' => 'cannot be uninstalled~~', + 'UI:Layout:ExtensionsDetails:BadgeMissingFromDisk' => 'missing from disk~~', + 'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~', + 'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~', + 'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~', + 'UI:Layout:ExtensionsDetails:MoreActions' => 'Show more actions~~', +]); diff --git a/dictionaries/ui/layouts/extensions-details/tr.dictionary.itop.extensions-details.php b/dictionaries/ui/layouts/extensions-details/tr.dictionary.itop.extensions-details.php new file mode 100644 index 0000000000..45ca6000a3 --- /dev/null +++ b/dictionaries/ui/layouts/extensions-details/tr.dictionary.itop.extensions-details.php @@ -0,0 +1,24 @@ + 'installed~~', + 'UI:Layout:ExtensionsDetails:BadgeToBeInstalled' => 'to be installed~~', + 'UI:Layout:ExtensionsDetails:BadgeNotInstalled' => 'not installed~~', + 'UI:Layout:ExtensionsDetails:BadgeToBeUninstalled' => 'to be uninstalled~~', + 'UI:Layout:ExtensionsDetails:BadgeNotUninstallable' => 'cannot be uninstalled~~', + 'UI:Layout:ExtensionsDetails:BadgeMissingFromDisk' => 'missing from disk~~', + 'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~', + 'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~', + 'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~', + 'UI:Layout:ExtensionsDetails:MoreActions' => 'Show more actions~~', +]); diff --git a/dictionaries/ui/layouts/extensions-details/zh_cn.dictionary.itop.extensions-details.php b/dictionaries/ui/layouts/extensions-details/zh_cn.dictionary.itop.extensions-details.php new file mode 100644 index 0000000000..afce37f0ac --- /dev/null +++ b/dictionaries/ui/layouts/extensions-details/zh_cn.dictionary.itop.extensions-details.php @@ -0,0 +1,24 @@ + 'installed~~', + 'UI:Layout:ExtensionsDetails:BadgeToBeInstalled' => 'to be installed~~', + 'UI:Layout:ExtensionsDetails:BadgeNotInstalled' => 'not installed~~', + 'UI:Layout:ExtensionsDetails:BadgeToBeUninstalled' => 'to be uninstalled~~', + 'UI:Layout:ExtensionsDetails:BadgeNotUninstallable' => 'cannot be uninstalled~~', + 'UI:Layout:ExtensionsDetails:BadgeMissingFromDisk' => 'missing from disk~~', + 'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~', + 'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~', + 'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~', + 'UI:Layout:ExtensionsDetails:MoreActions' => 'Show more actions~~', +]); diff --git a/lib/composer/autoload_classmap.php b/lib/composer/autoload_classmap.php index 52b87f481c..50b73aabc9 100644 --- a/lib/composer/autoload_classmap.php +++ b/lib/composer/autoload_classmap.php @@ -158,6 +158,8 @@ return array( 'Combodo\\iTop\\Application\\UI\\Base\\AbstractUIBlockFactory' => $baseDir . '/sources/Application/UI/Base/AbstractUIBlockFactory.php', 'Combodo\\iTop\\Application\\UI\\Base\\Component\\Alert\\Alert' => $baseDir . '/sources/Application/UI/Base/Component/Alert/Alert.php', 'Combodo\\iTop\\Application\\UI\\Base\\Component\\Alert\\AlertUIBlockFactory' => $baseDir . '/sources/Application/UI/Base/Component/Alert/AlertUIBlockFactory.php', + 'Combodo\\iTop\\Application\\UI\\Base\\Component\\Badge\\Badge' => $baseDir . '/sources/Application/UI/Base/Component/Badge/Badge.php', + 'Combodo\\iTop\\Application\\UI\\Base\\Component\\Badge\\BadgeUIBlockFactory' => $baseDir . '/sources/Application/UI/Base/Component/Badge/BadgeUIBlockFactory.php', 'Combodo\\iTop\\Application\\UI\\Base\\Component\\Breadcrumbs\\Breadcrumbs' => $baseDir . '/sources/Application/UI/Base/Component/Breadcrumbs/Breadcrumbs.php', 'Combodo\\iTop\\Application\\UI\\Base\\Component\\ButtonGroup\\ButtonGroup' => $baseDir . '/sources/Application/UI/Base/Component/ButtonGroup/ButtonGroup.php', 'Combodo\\iTop\\Application\\UI\\Base\\Component\\ButtonGroup\\ButtonGroupUIBlockFactory' => $baseDir . '/sources/Application/UI/Base/Component/ButtonGroup/ButtonGroupUIBlockFactory.php', @@ -274,6 +276,8 @@ return array( 'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Dashboard\\DashboardColumn' => $baseDir . '/sources/Application/UI/Base/Layout/Dashboard/DashboardColumn.php', 'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Dashboard\\DashboardLayout' => $baseDir . '/sources/Application/UI/Base/Layout/Dashboard/DashboardLayout.php', 'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Dashboard\\DashboardRow' => $baseDir . '/sources/Application/UI/Base/Layout/Dashboard/DashboardRow.php', + 'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Extension\\ExtensionDetails' => $baseDir . '/sources/Application/UI/Base/Layout/Extension/ExtensionDetails.php', + 'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Extension\\ExtensionDetailsUIBlockFactory' => $baseDir . '/sources/Application/UI/Base/Layout/Extension/ExtensionDetailsUIBlockFactory.php', 'Combodo\\iTop\\Application\\UI\\Base\\Layout\\MultiColumn\\Column\\Column' => $baseDir . '/sources/Application/UI/Base/Layout/MultiColumn/Column/Column.php', 'Combodo\\iTop\\Application\\UI\\Base\\Layout\\MultiColumn\\Column\\ColumnUIBlockFactory' => $baseDir . '/sources/Application/UI/Base/Layout/MultiColumn/Column/ColumnUIBlockFactory.php', 'Combodo\\iTop\\Application\\UI\\Base\\Layout\\MultiColumn\\MultiColumn' => $baseDir . '/sources/Application/UI/Base/Layout/MultiColumn/MultiColumn.php', @@ -621,6 +625,7 @@ return array( 'Combodo\\iTop\\Service\\Events\\iEventServiceSetup' => $baseDir . '/sources/Service/Events/iEventServiceSetup.php', 'Combodo\\iTop\\Service\\Import\\CSVImportPageProcessor' => $baseDir . '/sources/Service/Import/CSVImportPageProcessor.php', 'Combodo\\iTop\\Service\\InterfaceDiscovery\\InterfaceDiscovery' => $baseDir . '/sources/Service/InterfaceDiscovery/InterfaceDiscovery.php', + 'Combodo\\iTop\\Service\\Limits\\ExecutionLimits' => $baseDir . '/sources/Service/Limits/ExecutionLimits.php', 'Combodo\\iTop\\Service\\Links\\LinkSetDataTransformer' => $baseDir . '/sources/Service/Links/LinkSetDataTransformer.php', 'Combodo\\iTop\\Service\\Links\\LinkSetModel' => $baseDir . '/sources/Service/Links/LinkSetModel.php', 'Combodo\\iTop\\Service\\Links\\LinkSetRepository' => $baseDir . '/sources/Service/Links/LinkSetRepository.php', diff --git a/lib/composer/autoload_static.php b/lib/composer/autoload_static.php index 0837e69a7c..2c315e4f0e 100644 --- a/lib/composer/autoload_static.php +++ b/lib/composer/autoload_static.php @@ -559,6 +559,8 @@ class ComposerStaticInitfc0e9e9dea11dcbb6272414776c30685 'Combodo\\iTop\\Application\\UI\\Base\\AbstractUIBlockFactory' => __DIR__ . '/../..' . '/sources/Application/UI/Base/AbstractUIBlockFactory.php', 'Combodo\\iTop\\Application\\UI\\Base\\Component\\Alert\\Alert' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/Alert/Alert.php', 'Combodo\\iTop\\Application\\UI\\Base\\Component\\Alert\\AlertUIBlockFactory' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/Alert/AlertUIBlockFactory.php', + 'Combodo\\iTop\\Application\\UI\\Base\\Component\\Badge\\Badge' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/Badge/Badge.php', + 'Combodo\\iTop\\Application\\UI\\Base\\Component\\Badge\\BadgeUIBlockFactory' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/Badge/BadgeUIBlockFactory.php', 'Combodo\\iTop\\Application\\UI\\Base\\Component\\Breadcrumbs\\Breadcrumbs' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/Breadcrumbs/Breadcrumbs.php', 'Combodo\\iTop\\Application\\UI\\Base\\Component\\ButtonGroup\\ButtonGroup' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/ButtonGroup/ButtonGroup.php', 'Combodo\\iTop\\Application\\UI\\Base\\Component\\ButtonGroup\\ButtonGroupUIBlockFactory' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Component/ButtonGroup/ButtonGroupUIBlockFactory.php', @@ -675,6 +677,8 @@ class ComposerStaticInitfc0e9e9dea11dcbb6272414776c30685 'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Dashboard\\DashboardColumn' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/Dashboard/DashboardColumn.php', 'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Dashboard\\DashboardLayout' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/Dashboard/DashboardLayout.php', 'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Dashboard\\DashboardRow' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/Dashboard/DashboardRow.php', + 'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Extension\\ExtensionDetails' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/Extension/ExtensionDetails.php', + 'Combodo\\iTop\\Application\\UI\\Base\\Layout\\Extension\\ExtensionDetailsUIBlockFactory' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/Extension/ExtensionDetailsUIBlockFactory.php', 'Combodo\\iTop\\Application\\UI\\Base\\Layout\\MultiColumn\\Column\\Column' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/MultiColumn/Column/Column.php', 'Combodo\\iTop\\Application\\UI\\Base\\Layout\\MultiColumn\\Column\\ColumnUIBlockFactory' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/MultiColumn/Column/ColumnUIBlockFactory.php', 'Combodo\\iTop\\Application\\UI\\Base\\Layout\\MultiColumn\\MultiColumn' => __DIR__ . '/../..' . '/sources/Application/UI/Base/Layout/MultiColumn/MultiColumn.php', @@ -1022,6 +1026,7 @@ class ComposerStaticInitfc0e9e9dea11dcbb6272414776c30685 'Combodo\\iTop\\Service\\Events\\iEventServiceSetup' => __DIR__ . '/../..' . '/sources/Service/Events/iEventServiceSetup.php', 'Combodo\\iTop\\Service\\Import\\CSVImportPageProcessor' => __DIR__ . '/../..' . '/sources/Service/Import/CSVImportPageProcessor.php', 'Combodo\\iTop\\Service\\InterfaceDiscovery\\InterfaceDiscovery' => __DIR__ . '/../..' . '/sources/Service/InterfaceDiscovery/InterfaceDiscovery.php', + 'Combodo\\iTop\\Service\\Limits\\ExecutionLimits' => __DIR__ . '/../..' . '/sources/Service/Limits/ExecutionLimits.php', 'Combodo\\iTop\\Service\\Links\\LinkSetDataTransformer' => __DIR__ . '/../..' . '/sources/Service/Links/LinkSetDataTransformer.php', 'Combodo\\iTop\\Service\\Links\\LinkSetModel' => __DIR__ . '/../..' . '/sources/Service/Links/LinkSetModel.php', 'Combodo\\iTop\\Service\\Links\\LinkSetRepository' => __DIR__ . '/../..' . '/sources/Service/Links/LinkSetRepository.php', diff --git a/lib/composer/installed.php b/lib/composer/installed.php index 8c59fe7fcb..31a433d270 100644 --- a/lib/composer/installed.php +++ b/lib/composer/installed.php @@ -3,7 +3,7 @@ 'name' => 'combodo/itop', 'pretty_version' => 'dev-develop', 'version' => 'dev-develop', - 'reference' => '3ccbfb2b130419fec9d1158836395a13baa0ec4b', + 'reference' => '99cfe95c32885c98c66555bfec290df7d0e522a6', 'type' => 'project', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), @@ -24,7 +24,7 @@ 'combodo/itop' => array( 'pretty_version' => 'dev-develop', 'version' => 'dev-develop', - 'reference' => '3ccbfb2b130419fec9d1158836395a13baa0ec4b', + 'reference' => '99cfe95c32885c98c66555bfec290df7d0e522a6', 'type' => 'project', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), @@ -49,9 +49,9 @@ 'dev_requirement' => false, ), 'firebase/php-jwt' => array( - 'pretty_version' => 'v7.0.5', - 'version' => '7.0.5.0', - 'reference' => '47ad26bab5e7c70ae8a6f08ed25ff83631121380', + 'pretty_version' => 'v7.0.3', + 'version' => '7.0.3.0', + 'reference' => '28aa0694bcfdfa5e2959c394d5a1ee7a5083629e', 'type' => 'library', 'install_path' => __DIR__ . '/../firebase/php-jwt', 'aliases' => array(), @@ -76,9 +76,9 @@ 'dev_requirement' => false, ), 'guzzlehttp/psr7' => array( - 'pretty_version' => '2.9.0', - 'version' => '2.9.0.0', - 'reference' => '7d0ed42f28e42d61352a7a79de682e5e67fec884', + 'pretty_version' => '2.8.0', + 'version' => '2.8.0.0', + 'reference' => '21dc724a0583619cd1652f673303492272778051', 'type' => 'library', 'install_path' => __DIR__ . '/../guzzlehttp/psr7', 'aliases' => array(), @@ -94,9 +94,9 @@ 'dev_requirement' => false, ), 'league/oauth2-google' => array( - 'pretty_version' => '4.2.0', - 'version' => '4.2.0.0', - 'reference' => '72be69505f890ea8b6d4e716f619b3c10a1f5010', + 'pretty_version' => '4.1.0', + 'version' => '4.1.0.0', + 'reference' => '8b9bb43740ac6d994aca881a35f7bacbe98c0ffb', 'type' => 'library', 'install_path' => __DIR__ . '/../league/oauth2-google', 'aliases' => array(), @@ -105,7 +105,7 @@ 'nikic/php-parser' => array( 'pretty_version' => 'dev-master', 'version' => 'dev-master', - 'reference' => 'b27e577f70d2114b8ba96105e403017919a8611b', + 'reference' => 'b2cd0735eb27788d5d41fa3c2cfaa01a593fd7fb', 'type' => 'library', 'install_path' => __DIR__ . '/../nikic/php-parser', 'aliases' => array( @@ -312,9 +312,9 @@ 'dev_requirement' => false, ), 'symfony/cache' => array( - 'pretty_version' => 'v6.4.36', - 'version' => '6.4.36.0', - 'reference' => '5b94fba945d1f9e7929cffd50e7a17f1ac36f10b', + 'pretty_version' => 'v6.4.34', + 'version' => '6.4.34.0', + 'reference' => 'a0a1690543329685c044362c873b78c6de9d4faa', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/cache', 'aliases' => array(), @@ -345,9 +345,9 @@ 'dev_requirement' => false, ), 'symfony/console' => array( - 'pretty_version' => 'v6.4.36', - 'version' => '6.4.36.0', - 'reference' => '9f481cfb580db8bcecc9b2d4c63f3e13df022ad5', + 'pretty_version' => 'v6.4.34', + 'version' => '6.4.34.0', + 'reference' => '7b1f1c37eff5910ddda2831345467e593a5120ad', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/console', 'aliases' => array(), @@ -362,19 +362,10 @@ 'aliases' => array(), 'dev_requirement' => false, ), - 'symfony/debug-bundle' => array( - 'pretty_version' => 'v6.4.35', - 'version' => '6.4.35.0', - 'reference' => 'eb79084c2c9778559b21f61cb1507cbd580cc6e1', - 'type' => 'symfony-bundle', - 'install_path' => __DIR__ . '/../symfony/debug-bundle', - 'aliases' => array(), - 'dev_requirement' => true, - ), 'symfony/dependency-injection' => array( - 'pretty_version' => 'v6.4.36', - 'version' => '6.4.36.0', - 'reference' => 'cd7881a6dc84b780411199cd0584e1a53a3b9ba7', + 'pretty_version' => 'v6.4.34', + 'version' => '6.4.34.0', + 'reference' => '91e49958b8a6092e48e4711894a1aeb1b151c62a', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/dependency-injection', 'aliases' => array(), @@ -390,27 +381,27 @@ 'dev_requirement' => false, ), 'symfony/dotenv' => array( - 'pretty_version' => 'v6.4.36', - 'version' => '6.4.36.0', - 'reference' => 'cae019cc92a46fe9e498ea011107f26bdf5d897f', + 'pretty_version' => 'v6.4.30', + 'version' => '6.4.30.0', + 'reference' => '924edbc9631b75302def0258ed1697948b17baf6', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/dotenv', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/error-handler' => array( - 'pretty_version' => 'v6.4.36', - 'version' => '6.4.36.0', - 'reference' => '2ea68f0e1835ad6a126f93bbc14cd236c10ab361', + 'pretty_version' => 'v6.4.32', + 'version' => '6.4.32.0', + 'reference' => '8c18400784fcb014dc73c8d5601a9576af7f8ad4', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/error-handler', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/event-dispatcher' => array( - 'pretty_version' => 'v6.4.36', - 'version' => '6.4.36.0', - 'reference' => 'fc828863e26ceec86e2513b5e46aa0b149d76b69', + 'pretty_version' => 'v6.4.32', + 'version' => '6.4.32.0', + 'reference' => '99d7e101826e6610606b9433248f80c1997cd20b', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/event-dispatcher', 'aliases' => array(), @@ -450,36 +441,36 @@ 'dev_requirement' => false, ), 'symfony/form' => array( - 'pretty_version' => 'v6.4.36', - 'version' => '6.4.36.0', - 'reference' => '3a38a81150400f0a486f8963e21a195311b30b27', + 'pretty_version' => 'v6.4.34', + 'version' => '6.4.34.0', + 'reference' => 'ed9275a133809bb48d949ba6dfdc808a819ebea2', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/form', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/framework-bundle' => array( - 'pretty_version' => 'v6.4.36', - 'version' => '6.4.36.0', - 'reference' => '147b02cfa45dcc74a290462551f5ee5c7fa8ab17', + 'pretty_version' => 'v6.4.34', + 'version' => '6.4.34.0', + 'reference' => '5b5d19473f22d699811a41b01cef2462bc42b238', 'type' => 'symfony-bundle', 'install_path' => __DIR__ . '/../symfony/framework-bundle', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/http-foundation' => array( - 'pretty_version' => 'v6.4.35', - 'version' => '6.4.35.0', - 'reference' => 'cffffd0a2c037117b742b4f8b379a22a2a33f6d2', + 'pretty_version' => 'v6.4.34', + 'version' => '6.4.34.0', + 'reference' => '5bb346d1b4b2a616e5c3d99b3ee4d5810735c535', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/http-foundation', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/http-kernel' => array( - 'pretty_version' => 'v6.4.36', - 'version' => '6.4.36.0', - 'reference' => '4087ec02119de450e9ebb60806d69c6bb8c6e468', + 'pretty_version' => 'v6.4.34', + 'version' => '6.4.34.0', + 'reference' => '006a49fc4f41ee21a6ca61e69caed1c30b29f07c', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/http-kernel', 'aliases' => array(), @@ -495,9 +486,9 @@ 'dev_requirement' => false, ), 'symfony/mime' => array( - 'pretty_version' => 'v6.4.36', - 'version' => '6.4.36.0', - 'reference' => '9c31726137c70798f815fb98293ffb8a2a47694c', + 'pretty_version' => 'v6.4.34', + 'version' => '6.4.34.0', + 'reference' => '2b32fbbe10b36a8379efab6e702ad8b917151839', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/mime', 'aliases' => array(), @@ -522,35 +513,35 @@ 'dev_requirement' => false, ), 'symfony/polyfill-ctype' => array( - 'pretty_version' => 'v1.36.0', - 'version' => '1.36.0.0', - 'reference' => '141046a8f9477948ff284fa65be2095baafb94f2', + 'pretty_version' => 'v1.33.0', + 'version' => '1.33.0.0', + 'reference' => 'a3cc8b044a6ea513310cbd48ef7333b384945638', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-ctype', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/polyfill-intl-grapheme' => array( - 'pretty_version' => 'v1.36.0', - 'version' => '1.36.0.0', - 'reference' => 'ad1b7b9092976d6c948b8a187cec9faaea9ec1df', + 'pretty_version' => 'v1.33.0', + 'version' => '1.33.0.0', + 'reference' => '380872130d3a5dd3ace2f4010d95125fde5d5c70', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-intl-grapheme', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/polyfill-intl-icu' => array( - 'pretty_version' => 'v1.36.0', - 'version' => '1.36.0.0', - 'reference' => '3510b63d07376b04e57e27e82607d468bb134f78', + 'pretty_version' => 'v1.33.0', + 'version' => '1.33.0.0', + 'reference' => 'bfc8fa13dbaf21d69114b0efcd72ab700fb04d0c', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-intl-icu', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/polyfill-intl-idn' => array( - 'pretty_version' => 'v1.36.0', - 'version' => '1.36.0.0', + 'pretty_version' => 'v1.33.0', + 'version' => '1.33.0.0', 'reference' => '9614ac4d8061dc257ecc64cba1b140873dce8ad3', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-intl-idn', @@ -558,8 +549,8 @@ 'dev_requirement' => false, ), 'symfony/polyfill-intl-normalizer' => array( - 'pretty_version' => 'v1.36.0', - 'version' => '1.36.0.0', + 'pretty_version' => 'v1.33.0', + 'version' => '1.33.0.0', 'reference' => '3833d7255cc303546435cb650316bff708a1c75c', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-intl-normalizer', @@ -567,18 +558,18 @@ 'dev_requirement' => false, ), 'symfony/polyfill-mbstring' => array( - 'pretty_version' => 'v1.36.0', - 'version' => '1.36.0.0', - 'reference' => '6a21eb99c6973357967f6ce3708cd55a6bec6315', + 'pretty_version' => 'v1.33.0', + 'version' => '1.33.0.0', + 'reference' => '6d857f4d76bd4b343eac26d6b539585d2bc56493', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-mbstring', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/polyfill-php83' => array( - 'pretty_version' => 'v1.36.0', - 'version' => '1.36.0.0', - 'reference' => '3600c2cb22399e25bb226e4a135ce91eeb2a6149', + 'pretty_version' => 'v1.33.0', + 'version' => '1.33.0.0', + 'reference' => '17f6f9a6b1735c0f163024d959f700cfbc5155e5', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/polyfill-php83', 'aliases' => array(), @@ -611,19 +602,10 @@ 'aliases' => array(), 'dev_requirement' => false, ), - 'symfony/runtime' => array( - 'pretty_version' => 'v6.4.30', - 'version' => '6.4.30.0', - 'reference' => 'fb3149ee85d3b639dd3e49ea9dda05656f0537e3', - 'type' => 'composer-plugin', - 'install_path' => __DIR__ . '/../symfony/runtime', - 'aliases' => array(), - 'dev_requirement' => false, - ), 'symfony/security-core' => array( - 'pretty_version' => 'v6.4.36', - 'version' => '6.4.36.0', - 'reference' => '1b7db28bcc3655543abfe58764025aef563705cd', + 'pretty_version' => 'v6.4.31', + 'version' => '6.4.31.0', + 'reference' => 'fa269ad61a021cc54329dc96e57bed78ba720bfe', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/security-core', 'aliases' => array(), @@ -681,9 +663,9 @@ 'dev_requirement' => false, ), 'symfony/twig-bridge' => array( - 'pretty_version' => 'v6.4.36', - 'version' => '6.4.36.0', - 'reference' => '3ae963a108fd6fc14d09a7fe5e41fe64d8ac11ba', + 'pretty_version' => 'v6.4.34', + 'version' => '6.4.34.0', + 'reference' => '5169074f4a88dfb02eeccddaba78edfdf212a9b2', 'type' => 'symfony-bridge', 'install_path' => __DIR__ . '/../symfony/twig-bridge', 'aliases' => array(), @@ -699,36 +681,36 @@ 'dev_requirement' => false, ), 'symfony/validator' => array( - 'pretty_version' => 'v6.4.36', - 'version' => '6.4.36.0', - 'reference' => '14921e87b2bd69dfbd9757cdb1c6974a1316aac5', + 'pretty_version' => 'v6.4.34', + 'version' => '6.4.34.0', + 'reference' => '7c3897b7f739d4ab913481e680405ca82d08084d', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/validator', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/var-dumper' => array( - 'pretty_version' => 'v6.4.36', - 'version' => '6.4.36.0', - 'reference' => '7c8ad9ce4faf6c8a99948e70ce02b601a0439782', + 'pretty_version' => 'v6.4.32', + 'version' => '6.4.32.0', + 'reference' => '131fc9915e0343052af5ed5040401b481ca192aa', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/var-dumper', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/var-exporter' => array( - 'pretty_version' => 'v6.4.36', - 'version' => '6.4.36.0', - 'reference' => 'f9c4a9695a9e2bbc65c920e147d8d7ae28f8d79a', + 'pretty_version' => 'v6.4.26', + 'version' => '6.4.26.0', + 'reference' => '466fcac5fa2e871f83d31173f80e9c2684743bfc', 'type' => 'library', 'install_path' => __DIR__ . '/../symfony/var-exporter', 'aliases' => array(), 'dev_requirement' => false, ), 'symfony/web-profiler-bundle' => array( - 'pretty_version' => 'v6.4.36', - 'version' => '6.4.36.0', - 'reference' => '6f75b4c748886c8e04a3674225d00eaa51f3842d', + 'pretty_version' => 'v6.4.34', + 'version' => '6.4.34.0', + 'reference' => '848bc5d5745500f855bb201d57ae066fd7e67448', 'type' => 'symfony-bundle', 'install_path' => __DIR__ . '/../symfony/web-profiler-bundle', 'aliases' => array(), @@ -744,9 +726,9 @@ 'dev_requirement' => false, ), 'tecnickcom/tcpdf' => array( - 'pretty_version' => '6.11.2', - 'version' => '6.11.2.0', - 'reference' => 'e1e2ade18e574e963473f53271591edd8c0033ec', + 'pretty_version' => '6.11.0', + 'version' => '6.11.0.0', + 'reference' => '81172e58edb1cfae4019ef150ccbdc0e9a8c85c9', 'type' => 'library', 'install_path' => __DIR__ . '/../tecnickcom/tcpdf', 'aliases' => array(), @@ -762,9 +744,9 @@ 'dev_requirement' => false, ), 'twig/twig' => array( - 'pretty_version' => 'v3.24.0', - 'version' => '3.24.0.0', - 'reference' => 'a6769aefb305efef849dc25c9fd1653358c148f0', + 'pretty_version' => 'v3.23.0', + 'version' => '3.23.0.0', + 'reference' => 'a64dc5d2cc7d6cafb9347f6cd802d0d06d0351c9', 'type' => 'library', 'install_path' => __DIR__ . '/../twig/twig', 'aliases' => array(), diff --git a/log/index.php b/log/index.php deleted file mode 100644 index fcb6f20aff..0000000000 --- a/log/index.php +++ /dev/null @@ -1,3 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/setup/SetupDBBackup.php b/setup/SetupDBBackup.php new file mode 100644 index 0000000000..c6f95fa91a --- /dev/null +++ b/setup/SetupDBBackup.php @@ -0,0 +1,14 @@ +RequiresWritableConfig()) { - $sRelativePath = utils::GetConfigFilePathRelative(); - $oPage->error("Error: the configuration file '".$sRelativePath."' already exists and cannot be overwritten."); - $oPage->p("The wizard cannot modify the configuration file for you. If you want to upgrade ".ITOP_APPLICATION.", make sure that the file '".$sRelativePath."' can be modified by the web server."); - $oPage->output(); + $sRelativePath = utils::GetConfigFilePathRelative(ITOP_DEFAULT_ENV); + $sErrorMsg = "Error: the configuration file '".$sRelativePath."' already exists and cannot be overwritten."; + $sErrorMsg .= "The wizard cannot modify the configuration file for you. If you want to upgrade ".ITOP_APPLICATION.", make sure that the file '".$sRelativePath."' can be modified by the web server."; + throw new Exception($sErrorMsg); } else { $oStep->AsyncAction($oPage, $sActionCode, $aParams); } @@ -164,7 +163,7 @@ try { break; case 'toggle_use_symbolic_links': - $sUseSymbolicLinks = Utils::ReadParam('bUseSymbolicLinks', false); + $sUseSymbolicLinks = utils::ReadParam('bUseSymbolicLinks', false); $bUseSymbolicLinks = ($sUseSymbolicLinks === 'true'); MFCompiler::SetUseSymbolicLinksFlag($bUseSymbolicLinks); echo "toggle useSymbolicLinks flag : $bUseSymbolicLinks"; @@ -181,9 +180,5 @@ try { } if (function_exists('memory_get_peak_usage')) { - if ($sOperation == 'file') { - SetupLog::Info("loading file '$sFileName', peak memory usage. ".memory_get_peak_usage()); - } else { - SetupLog::Info("operation '$sOperation', peak memory usage. ".memory_get_peak_usage()); - } + SetupLog::Info("operation '$sOperation', peak memory usage. ".memory_get_peak_usage()); } diff --git a/setup/applicationinstaller.class.inc.php b/setup/applicationinstaller.class.inc.php index ca62935653..bb6d446f4b 100644 --- a/setup/applicationinstaller.class.inc.php +++ b/setup/applicationinstaller.class.inc.php @@ -1,1051 +1,26 @@ - -require_once(APPROOT.'setup/parameters.class.inc.php'); -require_once(APPROOT.'setup/xmldataloader.class.inc.php'); -require_once(APPROOT.'setup/backup.class.inc.php'); - /** - * The base class for the installation process. - * The installation process is split into a sequence of unitary steps - * for performance reasons (i.e; timeout, memory usage) and also in order - * to provide some feedback about the progress of the installation. + * Copyright (C) 2013-2026 Combodo SAS * - * This class can be used for a step by step interactive installation - * while displaying a progress bar, or in an unattended manner - * (for example from the command line), to run all the steps - * in one go. - * @copyright Copyright (C) 2010-2024 Combodo SAS - * @license http://opensource.org/licenses/AGPL-3.0 + * This file is part of iTop. + * + * iTop is free software; you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * iTop 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License */ -class ApplicationInstaller -{ - public const OK = 1; - public const ERROR = 2; - public const WARNING = 3; - public const INFO = 4; +require_once(APPROOT.'setup/sequencers/ApplicationInstallSequencer.php'); - /** @var \Parameters */ - protected $oParams; - protected static $bMetaModelStarted = false; - - /** - * @param \Parameters $oParams - * - * @throws \ConfigException - * @throws \CoreException - */ - public function __construct($oParams) - { - $this->oParams = $oParams; - - $aParamValues = $oParams->GetParamForConfigArray(); - $oConfig = new Config(); - $oConfig->UpdateFromParams($aParamValues, null); - utils::SetConfig($oConfig); - } - - /** - * @return string - */ - private function GetTargetEnv() - { - $sTargetEnvironment = $this->oParams->Get('target_env', ''); - if ($sTargetEnvironment !== '') { - return $sTargetEnvironment; - } - - return 'production'; - } - - /** - * @return string - */ - private function GetTargetDir() - { - $sTargetEnv = $this->GetTargetEnv(); - return 'env-'.$sTargetEnv; - } - - /** - * Runs all the installation steps in one go and directly outputs - * some information about the progress and the success of the various - * sequential steps. - * - * @param bool $bVerbose - * @param string|null $sMessage - * @param string|null $sInstallComment - * - * @return boolean True if the installation was successful, false otherwise - */ - public function ExecuteAllSteps($bVerbose = true, &$sMessage = null, $sInstallComment = null) - { - $sStep = ''; - $sStepLabel = ''; - $iOverallStatus = self::OK; - do { - if ($bVerbose) { - if ($sStep != '') { - echo "$sStepLabel\n"; - echo "Executing '$sStep'\n"; - } else { - echo "Starting the installation...\n"; - } - } - $aRes = $this->ExecuteStep($sStep, $sInstallComment); - $sStep = $aRes['next-step']; - $sStepLabel = $aRes['next-step-label']; - $sMessage = $aRes['message']; - if ($bVerbose) { - switch ($aRes['status']) { - case self::OK: - echo "Ok. ".$aRes['percentage-completed']." % done.\n"; - break; - - case self::ERROR: - $iOverallStatus = self::ERROR; - echo "Error: ".$aRes['message']."\n"; - break; - - case self::WARNING: - $iOverallStatus = self::WARNING; - echo "Warning: ".$aRes['message']."\n"; - echo $aRes['percentage-completed']." % done.\n"; - break; - - case self::INFO: - echo "Info: ".$aRes['message']."\n"; - echo $aRes['percentage-completed']." % done.\n"; - break; - } - } else { - switch ($aRes['status']) { - case self::ERROR: - $iOverallStatus = self::ERROR; - break; - case self::WARNING: - $iOverallStatus = self::WARNING; - break; - } - } - } while (($aRes['status'] != self::ERROR) && ($aRes['next-step'] != '')); - - return ($iOverallStatus == self::OK); - } - - private function GetConfig() - { - $sTargetEnvironment = $this->GetTargetEnv(); - $sConfigFile = APPCONF.$sTargetEnvironment.'/'.ITOP_CONFIG_FILE; - try { - $oConfig = new Config($sConfigFile); - } catch (Exception $e) { - return null; - } - - $aParamValues = $this->oParams->GetParamForConfigArray(); - $oConfig->UpdateFromParams($aParamValues); - - return $oConfig; - } - - /** - * Executes the next step of the installation and reports about the progress - * and the next step to perform - * - * @param string $sStep The identifier of the step to execute - * @param string|null $sInstallComment - * - * @return array (status => , message => , percentage-completed => , next-step => , next-step-label => ) - */ - public function ExecuteStep($sStep = '', $sInstallComment = null) - { - try { - $fStart = microtime(true); - SetupLog::Info("##### STEP {$sStep} start"); - $this->EnterReadOnlyMode(); - switch ($sStep) { - case '': - $aResult = [ - 'status' => self::OK, - 'message' => '', - 'percentage-completed' => 0, - 'next-step' => 'copy', - 'next-step-label' => 'Copying data model files', - ]; - - // Log the parameters... - $oDoc = new DOMDocument('1.0', 'UTF-8'); - $oDoc->preserveWhiteSpace = false; - $oDoc->formatOutput = true; - $this->oParams->ToXML($oDoc, null, 'installation'); - $sXML = $oDoc->saveXML(); - $sSafeXml = preg_replace("|([^<]*)|", "**removed**", $sXML); - SetupLog::Info("======= Installation starts =======\nParameters:\n$sSafeXml\n"); - - // Save the response file as a stand-alone file as well - $sFileName = 'install-'.date('Y-m-d'); - $index = 0; - while (file_exists(APPROOT.'log/'.$sFileName.'.xml')) { - $index++; - $sFileName = 'install-'.date('Y-m-d').'-'.$index; - } - file_put_contents(APPROOT.'log/'.$sFileName.'.xml', $sSafeXml); - - break; - - case 'copy': - $aPreinstall = $this->oParams->Get('preinstall'); - $aCopies = $aPreinstall['copies'] ?? []; - - self::DoCopy($aCopies); - $sReport = "Copying..."; - - $aResult = [ - 'status' => self::OK, - 'message' => $sReport, - ]; - if (isset($aPreinstall['backup'])) { - $aResult['next-step'] = 'backup'; - $aResult['next-step-label'] = 'Performing a backup of the database'; - $aResult['percentage-completed'] = 20; - } else { - $aResult['next-step'] = 'compile'; - $aResult['next-step-label'] = 'Compiling the data model'; - $aResult['percentage-completed'] = 20; - } - break; - - case 'backup': - $aPreinstall = $this->oParams->Get('preinstall'); - // __DB__-%Y-%m-%d - $sDestination = $aPreinstall['backup']['destination']; - $sSourceConfigFile = $aPreinstall['backup']['configuration_file']; - $aDBParams = $this->oParams->GetParamForConfigArray(); - $oTempConfig = new Config(); - $oTempConfig->UpdateFromParams($aDBParams); - $sMySQLBinDir = $this->oParams->Get('mysql_bindir', null); - self::DoBackup($oTempConfig, $sDestination, $sSourceConfigFile, $sMySQLBinDir); - - $aResult = [ - 'status' => self::OK, - 'message' => "Created backup", - 'next-step' => 'compile', - 'next-step-label' => 'Compiling the data model', - 'percentage-completed' => 20, - ]; - break; - - case 'compile': - $aSelectedModules = $this->oParams->Get('selected_modules'); - $sSourceDir = $this->oParams->Get('source_dir', 'datamodels/latest'); - $sExtensionDir = $this->oParams->Get('extensions_dir', 'extensions'); - $sTargetEnvironment = $this->GetTargetEnv(); - $sTargetDir = $this->GetTargetDir(); - $aMiscOptions = $this->oParams->Get('options', []); - - $bUseSymbolicLinks = null; - if ((isset($aMiscOptions['symlinks']) && $aMiscOptions['symlinks'])) { - if (function_exists('symlink')) { - $bUseSymbolicLinks = true; - SetupLog::Info("Using symbolic links instead of copying data model files (for developers only!)"); - } else { - SetupLog::Info("Symbolic links (function symlinks) does not seem to be supported on this platform (OS/PHP version)."); - } - } - - $aParamValues = $this->oParams->GetParamForConfigArray(); - self::DoCompile( - $aSelectedModules, - $sSourceDir, - $sExtensionDir, - $sTargetDir, - $sTargetEnvironment, - $bUseSymbolicLinks, - $aParamValues - ); - - $aResult = [ - 'status' => self::OK, - 'message' => '', - 'next-step' => 'db-schema', - 'next-step-label' => 'Updating database schema', - 'percentage-completed' => 40, - ]; - break; - - case 'db-schema': - $aSelectedModules = $this->oParams->Get('selected_modules', []); - $sTargetEnvironment = $this->GetTargetEnv(); - $sTargetDir = $this->GetTargetDir(); - $aParamValues = $this->oParams->GetParamForConfigArray(); - $bOldAddon = $this->oParams->Get('old_addon', false); - $sUrl = $this->oParams->Get('url', ''); - - self::DoUpdateDBSchema( - $aSelectedModules, - $sTargetDir, - $aParamValues, - $sTargetEnvironment, - $bOldAddon, - $sUrl - ); - - $aResult = [ - 'status' => self::OK, - 'message' => '', - 'next-step' => 'after-db-create', - 'next-step-label' => 'Creating profiles', - 'percentage-completed' => 60, - ]; - break; - - case 'after-db-create': - $sTargetEnvironment = $this->GetTargetEnv(); - $sTargetDir = $this->GetTargetDir(); - $aParamValues = $this->oParams->GetParamForConfigArray(); - $aAdminParams = $this->oParams->Get('admin_account'); - $sAdminUser = $aAdminParams['user']; - $sAdminPwd = $aAdminParams['pwd']; - $sAdminLanguage = $aAdminParams['language']; - $aSelectedModules = $this->oParams->Get('selected_modules', []); - $bOldAddon = $this->oParams->Get('old_addon', false); - - self::AfterDBCreate( - $sTargetDir, - $aParamValues, - $sAdminUser, - $sAdminPwd, - $sAdminLanguage, - $aSelectedModules, - $sTargetEnvironment, - $bOldAddon - ); - - $aResult = [ - 'status' => self::OK, - 'message' => '', - 'next-step' => 'load-data', - 'next-step-label' => 'Loading data', - 'percentage-completed' => 80, - ]; - break; - - case 'load-data': - $aSelectedModules = $this->oParams->Get('selected_modules'); - $sTargetEnvironment = $this->GetTargetEnv(); - $sTargetDir = $this->GetTargetDir(); - $aParamValues = $this->oParams->GetParamForConfigArray(); - $bOldAddon = $this->oParams->Get('old_addon', false); - $bSampleData = ($this->oParams->Get('sample_data', 0) == 1); - - self::DoLoadFiles( - $aSelectedModules, - $sTargetDir, - $aParamValues, - $sTargetEnvironment, - $bOldAddon, - $bSampleData - ); - - $aResult = [ - 'status' => self::INFO, - 'message' => 'All data loaded', - 'next-step' => 'create-config', - 'next-step-label' => 'Creating the configuration File', - 'percentage-completed' => 99, - ]; - break; - - case 'create-config': - $sTargetEnvironment = $this->GetTargetEnv(); - $sTargetDir = $this->GetTargetDir(); - $sPreviousConfigFile = $this->oParams->Get('previous_configuration_file', ''); - $sDataModelVersion = $this->oParams->Get('datamodel_version', '0.0.0'); - $bOldAddon = $this->oParams->Get('old_addon', false); - $aSelectedModuleCodes = $this->oParams->Get('selected_modules', []); - $aSelectedExtensionCodes = $this->oParams->Get('selected_extensions', []); - $aParamValues = $this->oParams->GetParamForConfigArray(); - - self::DoCreateConfig( - $sTargetDir, - $sPreviousConfigFile, - $sTargetEnvironment, - $sDataModelVersion, - $bOldAddon, - $aSelectedModuleCodes, - $aSelectedExtensionCodes, - $aParamValues, - $sInstallComment - ); - - $aResult = [ - 'status' => self::INFO, - 'message' => 'Configuration file created', - 'next-step' => '', - 'next-step-label' => 'Completed', - 'percentage-completed' => 100, - ]; - $this->ExitReadOnlyMode(); - break; - - default: - $aResult = [ - 'status' => self::ERROR, - 'message' => '', - 'next-step' => '', - 'next-step-label' => "Unknown setup step '$sStep'.", - 'percentage-completed' => 100, - ]; - break; - } - } catch (Exception $e) { - $aResult = [ - 'status' => self::ERROR, - 'message' => $e->getMessage(), - 'next-step' => '', - 'next-step-label' => '', - 'percentage-completed' => 100, - ]; - - SetupLog::Error('An exception occurred: '.$e->getMessage().' at line '.$e->getLine().' in file '.$e->getFile()); - $idx = 0; - // Log the call stack, but not the parameters since they may contain passwords or other sensitive data - SetupLog::Ok("Call stack:"); - foreach ($e->getTrace() as $aTrace) { - $sLine = empty($aTrace['line']) ? "" : $aTrace['line']; - $sFile = empty($aTrace['file']) ? "" : $aTrace['file']; - $sClass = empty($aTrace['class']) ? "" : $aTrace['class']; - $sType = empty($aTrace['type']) ? "" : $aTrace['type']; - $sFunction = empty($aTrace['function']) ? "" : $aTrace['function']; - $sVerb = empty($sClass) ? $sFunction : "$sClass{$sType}$sFunction"; - SetupLog::Ok("#$idx $sFile($sLine): $sVerb(...)"); - $idx++; - } - } finally { - $fDuration = round(microtime(true) - $fStart, 2); - SetupLog::Info("##### STEP {$sStep} duration: {$fDuration}s"); - } - - return $aResult; - } - - private function EnterReadOnlyMode() - { - if ($this->GetTargetEnv() != 'production') { - return; - } - - if (SetupUtils::IsInReadOnlyMode()) { - return; - } - - SetupUtils::EnterReadOnlyMode($this->GetConfig()); - } - - private function ExitReadOnlyMode() - { - if ($this->GetTargetEnv() != 'production') { - return; - } - - if (!SetupUtils::IsInReadOnlyMode()) { - return; - } - - SetupUtils::ExitReadOnlyMode(); - } - - protected static function DoCopy($aCopies) - { - $aReports = []; - foreach ($aCopies as $aCopy) { - $sSource = $aCopy['source']; - $sDestination = APPROOT.$aCopy['destination']; - - SetupUtils::builddir($sDestination); - SetupUtils::tidydir($sDestination); - SetupUtils::copydir($sSource, $sDestination); - $aReports[] = "'{$aCopy['source']}' to '{$aCopy['destination']}' (OK)"; - } - if (count($aReports) > 0) { - $sReport = "Copies: ".count($aReports).': '.implode('; ', $aReports); - } else { - $sReport = "No file copy"; - } - return $sReport; - } - - /** - * @param Config $oConfig - * @param string $sBackupFileFormat - * @param string $sSourceConfigFile - * @param string $sMySQLBinDir - * - * @throws \BackupException - * @throws \CoreException - * @throws \MySQLException - * @since 2.5.0 uses a {@link Config} object to store DB parameters - */ - protected static function DoBackup($oConfig, $sBackupFileFormat, $sSourceConfigFile, $sMySQLBinDir = null) - { - $oBackup = new SetupDBBackup($oConfig); - $sTargetFile = $oBackup->MakeName($sBackupFileFormat); - if (!empty($sMySQLBinDir)) { - $oBackup->SetMySQLBinDir($sMySQLBinDir); - } - - CMDBSource::InitFromConfig($oConfig); - $oBackup->CreateCompressedBackup($sTargetFile, $sSourceConfigFile); - } - - /** - * @param array $aSelectedModules - * @param string $sSourceDir - * @param string $sExtensionDir - * @param string $sTargetDir - * @param string $sEnvironment - * @param boolean $bUseSymbolicLinks - * @param array $aParamValues - * - * @return void - * @throws \ConfigException - * @throws \CoreException - * - * @since 3.1.0 N°2013 added the aParamValues param - */ - protected static function DoCompile($aSelectedModules, $sSourceDir, $sExtensionDir, $sTargetDir, $sEnvironment, $bUseSymbolicLinks = null, $aParamValues = []) - { - SetupLog::Info("Compiling data model."); - - require_once(APPROOT.'setup/modulediscovery.class.inc.php'); - require_once(APPROOT.'setup/modelfactory.class.inc.php'); - require_once(APPROOT.'setup/compiler.class.inc.php'); - - if (empty($sSourceDir) || empty($sTargetDir)) { - throw new Exception("missing parameter source_dir and/or target_dir"); - } - - $sSourcePath = APPROOT.$sSourceDir; - $aDirsToScan = [$sSourcePath]; - $sExtensionsPath = APPROOT.$sExtensionDir; - if (is_dir($sExtensionsPath)) { - // if the extensions dir exists, scan it for additional modules as well - $aDirsToScan[] = $sExtensionsPath; - } - $sExtraPath = APPROOT.'/data/'.$sEnvironment.'-modules/'; - if (is_dir($sExtraPath)) { - // if the extra dir exists, scan it for additional modules as well - $aDirsToScan[] = $sExtraPath; - } - $sTargetPath = APPROOT.$sTargetDir; - - if (!is_dir($sSourcePath)) { - throw new Exception("Failed to find the source directory '$sSourcePath', please check the rights of the web server"); - } - $bIsAlreadyInMaintenanceMode = SetupUtils::IsInMaintenanceMode(); - if (($sEnvironment == 'production') && !$bIsAlreadyInMaintenanceMode) { - $sConfigFilePath = utils::GetConfigFilePath($sEnvironment); - if (is_file($sConfigFilePath)) { - $oConfig = new Config($sConfigFilePath); - } else { - $oConfig = null; - } - - if (false === is_null($oConfig)) { - $oConfig->UpdateFromParams($aParamValues); - } - - SetupUtils::EnterMaintenanceMode($oConfig); - } - - if (!is_dir($sTargetPath)) { - if (!mkdir($sTargetPath)) { - throw new Exception("Failed to create directory '$sTargetPath', please check the rights of the web server"); - } else { - // adjust the rights if and only if the directory was just created - // owner:rwx user/group:rx - chmod($sTargetPath, 0755); - } - } elseif (substr($sTargetPath, 0, strlen(APPROOT)) == APPROOT) { - // If the directory is under the root folder - as expected - let's clean-it before compiling - SetupUtils::tidydir($sTargetPath); - } - - $oFactory = new ModelFactory($aDirsToScan); - - $oDictModule = new MFDictModule('dictionaries', 'iTop Dictionaries', APPROOT.'dictionaries'); - $oFactory->LoadModule($oDictModule); - - $sDeltaFile = APPROOT.'core/datamodel.core.xml'; - if (file_exists($sDeltaFile)) { - $oCoreModule = new MFCoreModule('core', 'Core Module', $sDeltaFile); - $oFactory->LoadModule($oCoreModule); - } - $sDeltaFile = APPROOT.'application/datamodel.application.xml'; - if (file_exists($sDeltaFile)) { - $oApplicationModule = new MFCoreModule('application', 'Application Module', $sDeltaFile); - $oFactory->LoadModule($oApplicationModule); - } - - $aModules = $oFactory->FindModules(); - - foreach ($aModules as $oModule) { - $sModule = $oModule->GetName(); - if (in_array($sModule, $aSelectedModules)) { - $oFactory->LoadModule($oModule); - } - } - // Dump the "reference" model, just before loading any actual delta - $oFactory->SaveToFile(utils::GetDataPath().'datamodel-'.$sEnvironment.'.xml'); - - $sDeltaFile = utils::GetDataPath().$sEnvironment.'.delta.xml'; - if (file_exists($sDeltaFile)) { - $oDelta = new MFDeltaModule($sDeltaFile); - $oFactory->LoadModule($oDelta); - $oFactory->SaveToFile(utils::GetDataPath().'datamodel-'.$sEnvironment.'-with-delta.xml'); - } - - $oMFCompiler = new MFCompiler($oFactory, $sEnvironment); - $oMFCompiler->Compile($sTargetPath, null, $bUseSymbolicLinks); - //$aCompilerLog = $oMFCompiler->GetLog(); - //SetupLog::Info(implode("\n", $aCompilerLog)); - SetupLog::Info("Data model successfully compiled to '$sTargetPath'."); - - $sCacheDir = APPROOT.'/data/cache-'.$sEnvironment.'/'; - SetupUtils::builddir($sCacheDir); - SetupUtils::tidydir($sCacheDir); - - // Special case to patch a ugly patch in itop-config-mgmt - $sFileToPatch = $sTargetPath.'/itop-config-mgmt-1.0.0/model.itop-config-mgmt.php'; - if (file_exists($sFileToPatch)) { - $sContent = file_get_contents($sFileToPatch); - - $sContent = str_replace("require_once(APPROOT.'modules/itop-welcome-itil/model.itop-welcome-itil.php');", "//\n// The line below is no longer needed in iTop 2.0 -- patched by the setup program\n// require_once(APPROOT.'modules/itop-welcome-itil/model.itop-welcome-itil.php');", $sContent); - - file_put_contents($sFileToPatch, $sContent); - } - - // Set an "Instance UUID" identifying this machine based on a file located in the data directory - $sInstanceUUIDFile = utils::GetDataPath().'instance.txt'; - SetupUtils::builddir(utils::GetDataPath()); - if (!file_exists($sInstanceUUIDFile)) { - $sIntanceUUID = utils::CreateUUID('filesystem'); - file_put_contents($sInstanceUUIDFile, $sIntanceUUID); - } - if (($sEnvironment == 'production') && !$bIsAlreadyInMaintenanceMode) { - SetupUtils::ExitMaintenanceMode(); - } - } - - /** - * @param $aSelectedModules - * @param $sModulesDir - * @param $aParamValues - * @param string $sTargetEnvironment - * @param bool $bOldAddon - * @param string $sAppRootUrl - * - * @throws \ConfigException - * @throws \CoreException - * @throws \MySQLException - */ - protected static function DoUpdateDBSchema($aSelectedModules, $sModulesDir, $aParamValues, $sTargetEnvironment = '', $bOldAddon = false, $sAppRootUrl = '') - { - /** - * @since 3.2.0 move the ContextTag init at the very beginning of the method - * @noinspection PhpUnusedLocalVariableInspection - */ - $oContextTag = new ContextTag(ContextTag::TAG_SETUP); - SetupLog::Info("Update Database Schema for environment '$sTargetEnvironment'."); - $sMode = $aParamValues['mode']; - $sDBPrefix = $aParamValues['db_prefix']; - $sDBName = $aParamValues['db_name']; - - $oConfig = new Config(); - $oConfig->UpdateFromParams($aParamValues, $sModulesDir); - - if ($bOldAddon) { - // Old version of the add-on for backward compatibility with pre-2.0 data models - $oConfig->SetAddons([]); - } - - $oProductionEnv = new RunTimeEnvironment($sTargetEnvironment); - $oProductionEnv->InitDataModel($oConfig, true); // load data model only - - // Migrate columns - self::MoveColumns($sDBPrefix); - - // Migrate application data format - // - // priv_internalUser caused troubles because MySQL transforms table names to lower case under Windows - // This becomes an issue when moving your installation data to/from Windows - // Starting 2.0, all table names must be lowercase - if ($sMode != 'install') { - SetupLog::Info("Renaming '{$sDBPrefix}priv_internalUser' into '{$sDBPrefix}priv_internaluser' (lowercase)"); - // This command will have no effect under Windows... - // and it has been written in two steps so as to make it work under windows! - CMDBSource::SelectDB($sDBName); - try { - $sRepair = "RENAME TABLE `{$sDBPrefix}priv_internalUser` TO `{$sDBPrefix}priv_internaluser_other`, `{$sDBPrefix}priv_internaluser_other` TO `{$sDBPrefix}priv_internaluser`"; - CMDBSource::Query($sRepair); - } catch (Exception $e) { - SetupLog::Info("Renaming '{$sDBPrefix}priv_internalUser' failed (already done in a previous upgrade?)"); - } - - // let's remove the records in priv_change which have no counterpart in priv_changeop - SetupLog::Info("Cleanup of '{$sDBPrefix}priv_change' to remove orphan records"); - CMDBSource::SelectDB($sDBName); - try { - $sTotalCount = "SELECT COUNT(*) FROM `{$sDBPrefix}priv_change`"; - $iTotalCount = (int)CMDBSource::QueryToScalar($sTotalCount); - SetupLog::Info("There is a total of $iTotalCount records in {$sDBPrefix}priv_change."); - - $sOrphanCount = "SELECT COUNT(c.id) FROM `{$sDBPrefix}priv_change` AS c left join `{$sDBPrefix}priv_changeop` AS o ON c.id = o.changeid WHERE o.id IS NULL"; - $iOrphanCount = (int)CMDBSource::QueryToScalar($sOrphanCount); - SetupLog::Info("There are $iOrphanCount useless records in {$sDBPrefix}priv_change (".sprintf('%.2f', ((100.0 * $iOrphanCount) / $iTotalCount))."%)"); - if ($iOrphanCount > 0) { - //N°3793 - if ($iOrphanCount > 100000) { - SetupLog::Info("There are too much useless records ($iOrphanCount) in {$sDBPrefix}priv_change. Cleanup cannot be done during setup."); - } else { - SetupLog::Info("Removing the orphan records..."); - $sCleanup = "DELETE FROM `{$sDBPrefix}priv_change` USING `{$sDBPrefix}priv_change` LEFT JOIN `{$sDBPrefix}priv_changeop` ON `{$sDBPrefix}priv_change`.id = `{$sDBPrefix}priv_changeop`.changeid WHERE `{$sDBPrefix}priv_changeop`.id IS NULL;"; - CMDBSource::Query($sCleanup); - SetupLog::Info("Cleanup completed successfully."); - } - } else { - SetupLog::Info("Ok, nothing to cleanup."); - } - } catch (Exception $e) { - SetupLog::Info("Cleanup of orphan records in `{$sDBPrefix}priv_change` failed: ".$e->getMessage()); - } - - } - - // Module specific actions (migrate the data) - // - $aAvailableModules = $oProductionEnv->AnalyzeInstallation(MetaModel::GetConfig(), APPROOT.$sModulesDir); - $oProductionEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'BeforeDatabaseCreation'); - - if (!$oProductionEnv->CreateDatabaseStructure(MetaModel::GetConfig(), $sMode)) { - throw new Exception("Failed to create/upgrade the database structure for environment '$sTargetEnvironment'"); - } - - // Set a DBProperty with a unique ID to identify this instance of iTop - $sUUID = DBProperty::GetProperty('database_uuid', ''); - if ($sUUID === '') { - $sUUID = utils::CreateUUID('database'); - DBProperty::SetProperty('database_uuid', $sUUID, 'Installation/upgrade of '.ITOP_APPLICATION, 'Unique ID of this '.ITOP_APPLICATION.' Database'); - } - - // priv_change now has an 'origin' field to distinguish between the various input sources - // Let's initialize the field with 'interactive' for all records were it's null - // Then check if some records should hold a different value, based on a pattern matching in the userinfo field - CMDBSource::SelectDB($sDBName); - try { - $sCount = "SELECT COUNT(*) FROM `{$sDBPrefix}priv_change` WHERE `origin` IS NULL"; - $iCount = (int)CMDBSource::QueryToScalar($sCount); - if ($iCount > 0) { - SetupLog::Info("Initializing '{$sDBPrefix}priv_change.origin' ($iCount records to update)"); - - // By default all uninitialized values are considered as 'interactive' - $sInit = "UPDATE `{$sDBPrefix}priv_change` SET `origin` = 'interactive' WHERE `origin` IS NULL"; - CMDBSource::Query($sInit); - - // CSV Import was identified by the comment at the end - $sInit = "UPDATE `{$sDBPrefix}priv_change` SET `origin` = 'csv-import.php' WHERE `userinfo` LIKE '%Web Service (CSV)'"; - CMDBSource::Query($sInit); - - // CSV Import was identified by the comment at the end - $sInit = "UPDATE `{$sDBPrefix}priv_change` SET `origin` = 'csv-interactive' WHERE `userinfo` LIKE '%(CSV)' AND origin = 'interactive'"; - CMDBSource::Query($sInit); - - // Syncho data sources were identified by the comment at the end - // Unfortunately the comment is localized, so we have to search for all possible patterns - $sCurrentLanguage = Dict::GetUserLanguage(); - $aSuffixes = []; - foreach (array_keys(Dict::GetLanguages()) as $sLangCode) { - Dict::SetUserLanguage($sLangCode); - $sSuffix = CMDBSource::Quote('%'.Dict::S('Core:SyncDataExchangeComment')); - $aSuffixes[$sSuffix] = true; - } - Dict::SetUserLanguage($sCurrentLanguage); - $sCondition = "`userinfo` LIKE ".implode(" OR `userinfo` LIKE ", array_keys($aSuffixes)); - - $sInit = "UPDATE `{$sDBPrefix}priv_change` SET `origin` = 'synchro-data-source' WHERE ($sCondition)"; - CMDBSource::Query($sInit); - - SetupLog::Info("Initialization of '{$sDBPrefix}priv_change.origin' completed."); - } else { - SetupLog::Info("'{$sDBPrefix}priv_change.origin' already initialized, nothing to do."); - } - } catch (Exception $e) { - SetupLog::Error("Initializing '{$sDBPrefix}priv_change.origin' failed: ".$e->getMessage()); - } - - // priv_async_task now has a 'status' field to distinguish between the various statuses rather than just relying on the date columns - // Let's initialize the field with 'planned' or 'error' for all records were it's null - CMDBSource::SelectDB($sDBName); - try { - $sCount = "SELECT COUNT(*) FROM `{$sDBPrefix}priv_async_task` WHERE `status` IS NULL"; - $iCount = (int)CMDBSource::QueryToScalar($sCount); - if ($iCount > 0) { - SetupLog::Info("Initializing '{$sDBPrefix}priv_async_task.status' ($iCount records to update)"); - - $sInit = "UPDATE `{$sDBPrefix}priv_async_task` SET `status` = 'planned' WHERE (`status` IS NULL) AND (`started` IS NULL)"; - CMDBSource::Query($sInit); - - $sInit = "UPDATE `{$sDBPrefix}priv_async_task` SET `status` = 'error' WHERE (`status` IS NULL) AND (`started` IS NOT NULL)"; - CMDBSource::Query($sInit); - - SetupLog::Info("Initialization of '{$sDBPrefix}priv_async_task.status' completed."); - } else { - SetupLog::Info("'{$sDBPrefix}priv_async_task.status' already initialized, nothing to do."); - } - } catch (Exception $e) { - SetupLog::Error("Initializing '{$sDBPrefix}priv_async_task.status' failed: ".$e->getMessage()); - } - - SetupLog::Info("Database Schema Successfully Updated for environment '$sTargetEnvironment'."); - } - - /** - * @param string $sDBPrefix - * - * @throws \CoreException - * @throws \MySQLException - */ - protected static function MoveColumns($sDBPrefix) - { - // In 2.6.0 the 'fields' attribute has been moved from Query to QueryOQL for dependencies reasons - ModuleInstallerAPI::MoveColumnInDB($sDBPrefix.'priv_query', 'fields', $sDBPrefix.'priv_query_oql', 'fields'); - } - - protected static function AfterDBCreate( - $sModulesDir, - $aParamValues, - $sAdminUser, - $sAdminPwd, - $sAdminLanguage, - $aSelectedModules, - $sTargetEnvironment, - $bOldAddon - ) { - /** - * @since 3.2.0 move the ContextTag init at the very beginning of the method - * @noinspection PhpUnusedLocalVariableInspection - */ - $oContextTag = new ContextTag(ContextTag::TAG_SETUP); - SetupLog::Info('After Database Creation'); - - $sMode = $aParamValues['mode']; - $oConfig = new Config(); - $oConfig->UpdateFromParams($aParamValues, $sModulesDir); - - if ($bOldAddon) { - // Old version of the add-on for backward compatibility with pre-2.0 data models - $oConfig->SetAddons([]); - } - - $oProductionEnv = new RunTimeEnvironment($sTargetEnvironment); - $oProductionEnv->InitDataModel($oConfig, true); // load data model and connect to the database - $oContextTag = new ContextTag(ContextTag::TAG_SETUP); - self::$bMetaModelStarted = true; // No need to reload the final MetaModel in case the installer runs synchronously - - // Perform here additional DB setup... profiles, etc... - // - $aAvailableModules = $oProductionEnv->AnalyzeInstallation(MetaModel::GetConfig(), APPROOT.$sModulesDir); - $oProductionEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'AfterDatabaseCreation'); - - $oProductionEnv->UpdatePredefinedObjects(); - - if ($sMode == 'install') { - if (!self::CreateAdminAccount(MetaModel::GetConfig(), $sAdminUser, $sAdminPwd, $sAdminLanguage)) { - throw(new Exception("Failed to create the administrator account '$sAdminUser'")); - } else { - SetupLog::Info("Administrator account '$sAdminUser' created."); - } - } - - // Perform final setup tasks here - // - $oProductionEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'AfterDatabaseSetup'); - } - - /** - * Helper function to create and administrator account for iTop - * @return boolean true on success, false otherwise - */ - protected static function CreateAdminAccount(Config $oConfig, $sAdminUser, $sAdminPwd, $sLanguage) - { - SetupLog::Info('CreateAdminAccount'); - - if (UserRights::CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage)) { - return true; - } else { - return false; - } - } - - protected static function DoLoadFiles( - $aSelectedModules, - $sModulesDir, - $aParamValues, - $sTargetEnvironment = 'production', - $bOldAddon = false, - $bSampleData = false - ) { - /** - * @since 3.2.0 move the ContextTag init at the very beginning of the method - * @noinspection PhpUnusedLocalVariableInspection - */ - $oContextTag = new ContextTag(ContextTag::TAG_SETUP); - - $oConfig = new Config(); - $oConfig->UpdateFromParams($aParamValues, $sModulesDir); - - if ($bOldAddon) { - // Old version of the add-on for backward compatibility with pre-2.0 data models - $oConfig->SetAddons([]); - } - - $oProductionEnv = new RunTimeEnvironment($sTargetEnvironment); - - //Load the MetaModel if needed (asynchronous mode) - if (!self::$bMetaModelStarted) { - $oProductionEnv->InitDataModel($oConfig, false); // load data model and connect to the database - - self::$bMetaModelStarted = true; // No need to reload the final MetaModel in case the installer runs synchronously - } - - $aAvailableModules = $oProductionEnv->AnalyzeInstallation($oConfig, APPROOT.$sModulesDir); - $oProductionEnv->LoadData($aAvailableModules, $aSelectedModules, $bSampleData); - - // Perform after dbload setup tasks here - // - $oProductionEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'AfterDataLoad'); - } - - /** - * @param string $sModulesDir - * @param string $sPreviousConfigFile - * @param string $sTargetEnvironment - * @param string $sDataModelVersion - * @param boolean $bOldAddon - * @param array $aSelectedModuleCodes - * @param array $aSelectedExtensionCodes - * @param array $aParamValues parameters array used to create config file using {@see Config::UpdateFromParams} - * - * @param null $sInstallComment - * - * @throws \ConfigException - * @throws \CoreException - * @throws \Exception - */ - protected static function DoCreateConfig( - $sModulesDir, - $sPreviousConfigFile, - $sTargetEnvironment, - $sDataModelVersion, - $bOldAddon, - $aSelectedModuleCodes, - $aSelectedExtensionCodes, - $aParamValues, - $sInstallComment = null - ) { - /** - * @since 3.2.0 move the ContextTag init at the very beginning of the method - * @noinspection PhpUnusedLocalVariableInspection - */ - $oContextTag = new ContextTag(ContextTag::TAG_SETUP); - - $aParamValues['selected_modules'] = implode(',', $aSelectedModuleCodes); - $sMode = $aParamValues['mode']; - - $bPreserveModuleSettings = false; - if ($sMode == 'upgrade') { - try { - $oOldConfig = new Config($sPreviousConfigFile); - $oConfig = clone($oOldConfig); - $bPreserveModuleSettings = true; - } catch (Exception $e) { - // In case the previous configuration is corrupted... start with a blank new one - $oConfig = new Config(); - } - } else { - $oConfig = new Config(); - // To preserve backward compatibility while upgrading to 2.0.3 (when tracking_level_linked_set_default has been introduced) - // the default value on upgrade differs from the default value at first install - $oConfig->Set('tracking_level_linked_set_default', LINKSET_TRACKING_NONE, 'first_install'); - } - - $oConfig->Set('access_mode', ACCESS_FULL); - // Final config update: add the modules - $oConfig->UpdateFromParams($aParamValues, $sModulesDir, $bPreserveModuleSettings); - if ($bOldAddon) { - // Old version of the add-on for backward compatibility with pre-2.0 data models - $oConfig->SetAddons([]); - } - - // Record which modules are installed... - $oProductionEnv = new RunTimeEnvironment($sTargetEnvironment); - $oProductionEnv->InitDataModel($oConfig, true); // load data model and connect to the database - - if (!$oProductionEnv->RecordInstallation($oConfig, $sDataModelVersion, $aSelectedModuleCodes, $aSelectedExtensionCodes, $sInstallComment)) { - throw new Exception("Failed to record the installation information"); - } - - // Make sure the root configuration directory exists - if (!file_exists(APPCONF)) { - mkdir(APPCONF); - chmod(APPCONF, 0770); // RWX for owner and group, nothing for others - SetupLog::Info("Created configuration directory: ".APPCONF); - } - - // Write the final configuration file - $sConfigFile = APPCONF.(($sTargetEnvironment == '') ? 'production' : $sTargetEnvironment).'/'.ITOP_CONFIG_FILE; - $sConfigDir = dirname($sConfigFile); - @mkdir($sConfigDir); - @chmod($sConfigDir, 0770); // RWX for owner and group, nothing for others - - $oConfig->WriteToFile($sConfigFile); - - // try to make the final config file read-only - @chmod($sConfigFile, 0440); // Read-only for owner and group, nothing for others - - // Ready to go !! - require_once(APPROOT.'core/dict.class.inc.php'); - MetaModel::ResetAllCaches(); - } -} - -class SetupDBBackup extends DBBackup -{ - protected function LogInfo($sMsg) - { - SetupLog::Ok('Info - '.$sMsg); - } - - protected function LogError($sMsg) - { - SetupLog::Ok('Error - '.$sMsg); - } -} +/** + * For compatibility with older scripts + */ +class_alias('ApplicationInstallSequencer', 'ApplicationInstaller'); diff --git a/setup/appupgradecopy.php b/setup/appupgradecopy.php index e271664707..0d6049e7c6 100644 --- a/setup/appupgradecopy.php +++ b/setup/appupgradecopy.php @@ -17,5 +17,10 @@ function AppUpgradeCopyFiles($sSourceDir) $sSource = realpath($sSourceDir.'/datamodels/2.x/itop-core-update'); if ($sSource !== false) { CoreUpdater::CopyDir($sSource, APPROOT.'env-production/itop-core-update'); + } else { + $sSource = realpath($sSourceDir.'/datamodels/1.x/itop-core-update'); + if ($sSource !== false) { + CoreUpdater::CopyDir($sSource, APPROOT.'env-production/itop-core-update'); + } } } diff --git a/setup/backup.class.inc.php b/setup/backup.class.inc.php index feb9f84a88..f2abb661f3 100644 --- a/setup/backup.class.inc.php +++ b/setup/backup.class.inc.php @@ -136,7 +136,7 @@ class DBBackup /** * Create a normalized backup name, depending on the current date/time and Database * - * @param string sMySQLBinDir Name and path, eventually containing itop placeholders + time formatting specs + * @param string $sMySQLBinDir Name and path, eventually containing itop placeholders + time formatting specs */ public function SetMySQLBinDir($sMySQLBinDir) { diff --git a/setup/compat/domcompat.php b/setup/compat/domcompat.php index a98d58a408..cfba8dd45c 100644 --- a/setup/compat/domcompat.php +++ b/setup/compat/domcompat.php @@ -29,7 +29,7 @@ if (!class_exists('DOMDocument')) { */ class DOMDocument { - public function __construct() + public function __construct(string $version = "1.0", string $encoding = "") { throw new Exception('The dom extension is not enabled'); } @@ -45,7 +45,7 @@ if (!class_exists('DOMElement')) { */ class DOMElement { - public function __construct() + public function __construct(string $qualifiedName, ?string $value = null, string $namespace = "") { throw new Exception('The dom extension is not enabled'); } diff --git a/setup/compiler.class.inc.php b/setup/compiler.class.inc.php index 89687d5c5c..a51cd4862d 100644 --- a/setup/compiler.class.inc.php +++ b/setup/compiler.class.inc.php @@ -21,8 +21,8 @@ use Combodo\iTop\Application\Branding; use Combodo\iTop\Application\WebPage\iTopWebPage; use Combodo\iTop\Application\WebPage\Page; -use Combodo\iTop\DesignElement; use Combodo\iTop\DesignDocument; +use Combodo\iTop\DesignElement; use Combodo\iTop\PropertyType\PropertyTypeDesign; require_once(APPROOT.'setup/setuputils.class.inc.php'); @@ -187,19 +187,6 @@ class MFCompiler return $this->aLog; } - /** - * @return bool if flag is present true, false otherwise - * - * @uses \file_exists() - * @uses USE_SYMBOLIC_LINKS_FILE_PATH - * - * @since 3.0.0 N°4092 - */ - public static function IsUseSymbolicLinksFlagPresent(): bool - { - return (file_exists(static::USE_SYMBOLIC_LINKS_FILE_PATH)); - } - /** * This is to check if the functionality can be used. As this is really only useful for developers, * this is strictly limited and not available on any iTop instance ! @@ -214,17 +201,22 @@ class MFCompiler * * @since 3.0.0 N°4092 */ - public static function CanUseSymbolicLinksFlagBeUsed(): bool + public static function CanUseSymbolicLinks(): bool { - if (false === utils::IsDevelopmentEnvironment()) { - return false; - } + return utils::IsDevelopmentEnvironment(); + } - if (false === function_exists('symlink')) { - return false; - } - - return true; + /** + * @return bool if flag is present true, false otherwise + * + * @uses \file_exists() + * @uses USE_SYMBOLIC_LINKS_FILE_PATH + * + * @since 3.0.0 N°4092 + */ + public static function UseSymbolicLinks(): bool + { + return (file_exists(static::USE_SYMBOLIC_LINKS_FILE_PATH)); } /** @@ -236,7 +228,7 @@ class MFCompiler */ public static function SetUseSymbolicLinksFlag(bool $bUseSymbolicLinks): void { - $bIsUseSymlinksFlagPresent = (static::IsUseSymbolicLinksFlagPresent()); + $bIsUseSymlinksFlagPresent = self::UseSymbolicLinks(); if ($bUseSymbolicLinks) { if ($bIsUseSymlinksFlagPresent) { @@ -279,11 +271,11 @@ class MFCompiler * @return void * @throws Exception */ - public function Compile($sTargetDir, $oP = null, $bUseSymbolicLinks = null, $bSkipTempDir = false) + public function Compile($sTargetDir, $oP = null, $bUseSymbolicLinks = null, $bSkipTempDir = false, $bEnterMaintenanceMode = true) { if (is_null($bUseSymbolicLinks)) { $bUseSymbolicLinks = false; - if (self::CanUseSymbolicLinksFlagBeUsed() && self::IsUseSymbolicLinksFlagPresent()) { + if (self::CanUseSymbolicLinks() && self::UseSymbolicLinks()) { // We are only overriding the useSymLinks option if the consumer didn't specify anything // The toolkit always send this parameter for example, but not the Designer Connector $bUseSymbolicLinks = true; @@ -298,8 +290,7 @@ class MFCompiler } else { $oConfig = null; } - if (($this->sEnvironment == 'production') && !$bIsAlreadyInMaintenanceMode) { - + if (($this->sEnvironment == ITOP_DEFAULT_ENV) && !$bIsAlreadyInMaintenanceMode && $bEnterMaintenanceMode) { SetupUtils::EnterMaintenanceMode($oConfig); } if ($bUseSymbolicLinks || $bSkipTempDir) { @@ -322,7 +313,7 @@ class MFCompiler // Cleanup the temporary directory SetupUtils::rrmdir($sTempTargetDir); } - if (($this->sEnvironment == 'production') && !$bIsAlreadyInMaintenanceMode) { + if (($this->sEnvironment == ITOP_DEFAULT_ENV) && !$bIsAlreadyInMaintenanceMode && $bEnterMaintenanceMode) { SetupUtils::ExitMaintenanceMode(); } throw $e; @@ -332,7 +323,7 @@ class MFCompiler // Move the results to the target directory SetupUtils::movedir($sTempTargetDir, $sFinalTargetDir); } - if (($this->sEnvironment == 'production') && !$bIsAlreadyInMaintenanceMode) { + if (($this->sEnvironment == ITOP_DEFAULT_ENV) && !$bIsAlreadyInMaintenanceMode && $bEnterMaintenanceMode) { SetupUtils::ExitMaintenanceMode(); } @@ -1571,13 +1562,6 @@ EOF; foreach ($aStatesOrder as $sState => $foo) { $oState = $aStates[$sState]; $oInitialStatePath = $oState->GetOptionalElement('initial_state_path'); - if ($oInitialStatePath) { - $aInitialStatePath = []; - foreach ($oInitialStatePath->getElementsByTagName('state_ref') as $oIntermediateState) { - $aInitialStatePath[] = "'".$oIntermediateState->GetText()."'"; - } - $sInitialStatePath = 'Array('.implode(', ', $aInitialStatePath).')'; - } $sLifecycle .= " MetaModel::Init_DefineState(\n"; $sLifecycle .= " \"".$sState."\",\n"; @@ -1606,6 +1590,11 @@ EOF; $sLifecycle .= " ),\n"; if (!is_null($oInitialStatePath)) { + $aInitialStatePath = []; + foreach ($oInitialStatePath->getElementsByTagName('state_ref') as $oIntermediateState) { + $aInitialStatePath[] = "'".$oIntermediateState->GetText()."'"; + } + $sInitialStatePath = 'Array('.implode(', ', $aInitialStatePath).')'; $sLifecycle .= " \"initial_state_path\" => $sInitialStatePath,\n"; } $sLifecycle .= " )\n"; @@ -2496,6 +2485,8 @@ EOF // Generate SCSS declaration $sScss = ""; + $sMainColorCssVariableName = null; + $sComplementaryColorCssVariableName = null; if ($bHasAtLeastOneColor) { if ($bHasMainColor) { $sMainColorScssVariableName = "\$$sCssRegularClass--main-color"; @@ -2512,8 +2503,10 @@ EOF $sCssAlternativeClassComplementaryColorDeclaration = "--ibo-complementary-color: #{{$sMainColorScssVariableName}};"; } else { $sMainColorScssVariableDeclaration = null; + $sMainColorCssVariableDeclaration = null; $sCssRegularClassMainColorDeclaration = null; + $sCssRegularClassMainColor100Declaration = null; $sCssRegularClassMainColor900Declaration = null; $sCssAlternativeClassComplementaryColorDeclaration = null; @@ -2656,6 +2649,9 @@ CSS; $oDefNode = $oXMLDoc->importNode($oNode, true); // layout, cells, etc Nodes and below $oRootNode->appendChild($oDefNode); } + if (!is_dir($sTempTargetDir.'/'.$sModuleRelativeDir)) { + SetupUtils::builddir($sTempTargetDir.'/'.$sModuleRelativeDir); + } $oXMLDoc->save($sTempTargetDir.'/'.$sModuleRelativeDir.'/'.$sFileName); } $sNewMenu = "new DashboardMenuNode('$sMenuId', $sTemplateSpec, $sParentSpec, $fRank {$sOptionalEnableParams});"; @@ -3362,6 +3358,9 @@ EOF; $bDataXmlPrecompiledFileExists = false; clearstatcache(); + + $iDataXmlFileLastModified = 0; + $sDataXmlProvidedPrecompiledFile = ''; if (!empty($sPrecompiledFileUri)) { $sDataXmlProvidedPrecompiledFile = $sTempTargetDir.DIRECTORY_SEPARATOR.$sPrecompiledFileUri; $bDataXmlPrecompiledFileExists = file_exists($sDataXmlProvidedPrecompiledFile) ; @@ -3375,7 +3374,6 @@ EOF; APPROOT.DIRECTORY_SEPARATOR.'extensions/', ]; - $iDataXmlFileLastModified = 0; foreach ($aDirToCheck as $sDir) { $sCurrentFile = $sDir.DIRECTORY_SEPARATOR.$sPrecompiledFileUri; if (is_file($sCurrentFile)) { diff --git a/setup/email.test.php b/setup/email.test.php index 184a2124ad..e5df5a2751 100644 --- a/setup/email.test.php +++ b/setup/email.test.php @@ -34,7 +34,7 @@ require_once(APPROOT.'/application/startup.inc.php'); require_once(APPROOT.'/application/loginwebpage.class.inc.php'); LoginWebPage::DoLogin(true); // Check user rights and prompt if needed (must be admin) -$sOperation = Utils::ReadParam('operation', 'step1'); +$sOperation = utils::ReadParam('operation', 'step1'); $oP = new SetupPage('iTop email test utility'); // Although this page doesn't expose sensitive info, with it we can send multiple emails @@ -208,7 +208,7 @@ function DisplayStep2(SetupPage $oP, $sFrom, $sTo) $oP->add("

Sending an email to '".htmlentities($sTo, ENT_QUOTES, 'utf-8')."'... (From: '".htmlentities($sFrom, ENT_QUOTES, 'utf-8')."')

\n"); $oP->add("
\n"); - $oEmail = new Email(); + $oEmail = new EMail(); $oEmail->SetRecipientTO($sTo); $oEmail->SetRecipientFrom($sFrom); $oEmail->SetSubject("Test iTop"); @@ -256,8 +256,8 @@ try { case 'step2': $oP->no_cache(); - $sTo = Utils::ReadParam('to', '', false, 'raw_data'); - $sFrom = Utils::ReadParam('from', '', false, 'raw_data'); + $sTo = utils::ReadParam('to', '', false, 'raw_data'); + $sFrom = utils::ReadParam('from', '', false, 'raw_data'); DisplayStep2($oP, $sFrom, $sTo); break; diff --git a/setup/extensionsmap.class.inc.php b/setup/extensionsmap.class.inc.php index 134812d81d..f8388ead9a 100644 --- a/setup/extensionsmap.class.inc.php +++ b/setup/extensionsmap.class.inc.php @@ -3,143 +3,11 @@ use Combodo\iTop\Setup\ModuleDiscovery\ModuleFileReader; use Combodo\iTop\Setup\ModuleDiscovery\ModuleFileReaderException; +require_once(APPROOT.'/setup/itopextension.class.inc.php'); require_once(APPROOT.'/setup/parameters.class.inc.php'); require_once(APPROOT.'/core/cmdbsource.class.inc.php'); require_once(APPROOT.'/setup/modulediscovery.class.inc.php'); require_once(APPROOT.'/setup/moduleinstaller.class.inc.php'); -/** - * Basic helper class to describe an extension, with some characteristics and a list of modules - */ -class iTopExtension -{ - public const SOURCE_WIZARD = 'datamodels'; - public const SOURCE_MANUAL = 'extensions'; - public const SOURCE_REMOTE = 'data'; - - /** - * @var string - */ - public $sCode; - - /** - * @var string - */ - public $sVersion; - - /** - * @var string - */ - public $sInstalledVersion; - - /** - * @var string - */ - public $sLabel; - - /** - * @var string - */ - public $sDescription; - - /** - * @var string - */ - public $sSource; - - /** - * @var bool - */ - public $bMandatory; - - /** - * @var string - */ - public $sMoreInfoUrl; - - /** - * @var bool - */ - public $bMarkedAsChosen; - /** - * If null, check if at least one module cannot be uninstalled - * @var bool|null - */ - public ?bool $bCanBeUninstalled = null; - - /** - * @var bool - */ - public $bVisible; - - /** - * @var string[] - */ - public $aModules; - - /** - * @var string[] - */ - public $aModuleVersion; - - /** - * @var string[] - */ - public $aModuleInfo; - - /** - * @var string - */ - public $sSourceDir; - - /** - * - * @var string[] - */ - public $aMissingDependencies; - /** - * @var bool - */ - public bool $bInstalled = false; - /** - * @var bool - */ - public bool $bRemovedFromDisk = false; - - public function __construct() - { - $this->sCode = ''; - $this->sLabel = ''; - $this->sDescription = ''; - $this->sSource = self::SOURCE_WIZARD; - $this->bMandatory = false; - $this->sMoreInfoUrl = ''; - $this->bMarkedAsChosen = false; - $this->sVersion = ITOP_VERSION; - $this->sInstalledVersion = ''; - $this->aModules = []; - $this->aModuleVersion = []; - $this->aModuleInfo = []; - $this->sSourceDir = ''; - $this->bVisible = true; - $this->aMissingDependencies = []; - } - - /** - * @since 3.3.0 - * @return bool - */ - public function CanBeUninstalled(): bool - { - if (!is_null($this->bCanBeUninstalled)) { - return $this->bCanBeUninstalled; - } - foreach ($this->aModuleInfo as $sModuleCode => $aModuleInfo) { - $this->bCanBeUninstalled = $aModuleInfo['uninstallable'] === 'yes'; - return $this->bCanBeUninstalled; - } - return true; - } -} /** * Helper class to discover all available extensions on a given iTop system @@ -148,49 +16,80 @@ class iTopExtensionsMap { /** * The list of all discovered extensions - * @param string $sFromEnvironment The environment to scan - * @param bool $bNormailizeOldExtension true to "magically" convert some well-known old extensions (i.e. a set of modules) to the new iTopExtension format - * @return void + * @var array $aExtensions */ protected $aExtensions; /** * The list of all currently installed extensions - * @var array|null + * @var array $aInstalledExtensions */ - protected ?array $aInstalledExtensions = null; + protected array $aInstalledExtensions; + protected array $aExtensionsByCode; /** * The list of directories browsed using the ReadDir method when building the map * @var string[] */ protected $aScannedDirs; - public function __construct($sFromEnvironment = 'production', $aExtraDirs = []) + /** @var bool $bHasXmlInstallationFile : false when legacy 1.x package with no installation.xml */ + protected $bHasXmlInstallationFile = true; + + //extension dirs apart from package + protected array $aExtraDirs = []; + + /** + * The list of all discovered extensions + * + * @param string $sFromEnvironment The environment to scan + * @param array $aExtraDirs extensions dir to scan + * @param array $aExtraDirs extensions dir to scan + * @param string|null $sAppRootForTests + * + * @return void + */ + public function __construct(string $sFromEnvironment = ITOP_DEFAULT_ENV, array $aExtraDirs = [], ?string $sAppRootForTests = null) { $this->aExtensions = []; + $this->aExtensionsByCode = []; $this->aScannedDirs = []; - $this->ScanDisk($sFromEnvironment); + + $sAppRoot = $sAppRootForTests ?? APPROOT; + $this->ScanDisk($sFromEnvironment, $sAppRoot); + + $this->aExtraDirs = $aExtraDirs; + if (is_dir($sAppRoot.'extensions')) { + $this->aExtraDirs [] = $sAppRoot.'extensions'; + } + if (is_dir($sAppRoot.'data/'.$sFromEnvironment.'-modules')) { + $this->aExtraDirs [] = $sAppRoot.'data/'.$sFromEnvironment.'-modules'; + } + foreach ($aExtraDirs as $sDir) { $this->ReadDir($sDir, iTopExtension::SOURCE_REMOTE); } - $this->CheckDependencies($sFromEnvironment); + $this->CheckDependencies($sAppRoot); } /** * Populate the list of available (pseudo)extensions by scanning the disk * where the iTop files are located * @param string $sEnvironment + * @param string $sAppRoot * @return void */ - protected function ScanDisk($sEnvironment) + protected function ScanDisk($sEnvironment, string $sAppRoot) { - if (!$this->ReadInstallationWizard(APPROOT.'/datamodels/2.x') && !$this->ReadInstallationWizard(APPROOT.'/datamodels/2.x')) { - if (!$this->ReadDir(APPROOT.'/datamodels/2.x', iTopExtension::SOURCE_WIZARD)) { - $this->ReadDir(APPROOT.'/datamodels/1.x', iTopExtension::SOURCE_WIZARD); + if (!$this->ReadInstallationWizard($sAppRoot.'/datamodels/2.x')) { + $this->bHasXmlInstallationFile = false; + //no installation xml found in 2.x: let's read all extensions in 2.x first + if (!$this->ReadDir($sAppRoot.'datamodels/2.x', iTopExtension::SOURCE_WIZARD)) { + //nothing found in 2.x : fallback read in 1.x (flat structure) + $this->ReadDir($sAppRoot.'datamodels/1.x', iTopExtension::SOURCE_WIZARD); } } - $this->ReadDir(APPROOT.'/extensions', iTopExtension::SOURCE_MANUAL); - $this->ReadDir(APPROOT.'/data/'.$sEnvironment.'-modules', iTopExtension::SOURCE_REMOTE); + $this->ReadDir($sAppRoot.'extensions', iTopExtension::SOURCE_MANUAL); + $this->ReadDir($sAppRoot.'data/'.$sEnvironment.'-modules', iTopExtension::SOURCE_REMOTE); } /** @@ -205,41 +104,86 @@ class iTopExtensionsMap return false; } + $aModuleConfigs = []; + $this->ListModuleFiles(basename($sDir), dirname($sDir), $aModuleConfigs); + $oXml = new XMLParameters($sDir.'/installation.xml'); foreach ($oXml->Get('steps') as $aStepInfo) { if (array_key_exists('options', $aStepInfo)) { - $this->ProcessWizardChoices($aStepInfo['options']); + $this->ProcessWizardChoices($aStepInfo['options'], $aModuleConfigs); } if (array_key_exists('alternatives', $aStepInfo)) { - $this->ProcessWizardChoices($aStepInfo['alternatives']); + $this->ProcessWizardChoices($aStepInfo['alternatives'], $aModuleConfigs); } } + return true; } + private function ListModuleFiles(string $sRelDir, string $sRootDir, array &$aRes): void + { + $sDirectory = $sRootDir.'/'.$sRelDir; + + if ($hDir = opendir($sDirectory)) { + // This is the correct way to loop over the directory. (according to the documentation) + while (($sFile = readdir($hDir)) !== false) { + $aMatches = []; + if (is_dir($sDirectory.'/'.$sFile)) { + if (($sFile != '.') && ($sFile != '..') && ($sFile != '.svn') && ($sFile != 'vendor')) { + $this->ListModuleFiles($sRelDir.'/'.$sFile, $sRootDir, $aRes); + } + } elseif (preg_match('/^module\.(.*).php$/i', $sFile, $aMatches)) { + try { + $aModuleInfo = ModuleFileReader::GetInstance()->ReadModuleFileInformation($sDirectory.'/'.$sFile); + $sModuleId = $aModuleInfo[ModuleFileReader::MODULE_INFO_ID]; + list($sModuleName, $sModuleVersion) = ModuleDiscovery::GetModuleName($sModuleId); + $aModuleConfig = $aModuleInfo[ModuleFileReader::MODULE_INFO_CONFIG]; + $aModuleConfig['module_version'] = $sModuleVersion; + $aRes[$sModuleName] = $aModuleConfig; + } catch (ModuleFileReaderException $e) { + continue; + } + } + } + closedir($hDir); + } + } + /** * Helper to process a "choice" array read from the installation.xml file * @param array $aChoices + * @param array $aModuleConfigs * @return void */ - protected function ProcessWizardChoices($aChoices) + protected function ProcessWizardChoices($aChoices, $aModuleConfigs) { foreach ($aChoices as $aChoiceInfo) { if (array_key_exists('extension_code', $aChoiceInfo)) { $oExtension = new iTopExtension(); $oExtension->sCode = $aChoiceInfo['extension_code']; + $oExtension->bCanBeUninstalled = !isset($aChoiceInfo['uninstallable']) || $aChoiceInfo['uninstallable'] === 'yes'; $oExtension->sLabel = $aChoiceInfo['title']; $oExtension->sDescription = $aChoiceInfo['description']; if (array_key_exists('modules', $aChoiceInfo)) { // Some wizard choices are not associated with any module $oExtension->aModules = $aChoiceInfo['modules']; + foreach ($oExtension->aModules as $sModuleName) { + $aCurrentModuleConfig = $aModuleConfigs[$sModuleName] ?? null; + if (is_null($aCurrentModuleConfig)) { + IssueLog::Debug("Installation choice comes with missing module file", null, ["choice" => $oExtension->sCode, 'module' => $sModuleName]); + continue; + } + $oExtension->aModuleVersion[$sModuleName] = $aCurrentModuleConfig['module_version']; + unset($aCurrentModuleConfig['module_version']); + $oExtension->aModuleInfo[$sModuleName] = $aCurrentModuleConfig; + } } if (array_key_exists('sub_options', $aChoiceInfo)) { if (array_key_exists('options', $aChoiceInfo['sub_options'])) { - $this->ProcessWizardChoices($aChoiceInfo['sub_options']['options']); + $this->ProcessWizardChoices($aChoiceInfo['sub_options']['options'], $aModuleConfigs); } if (array_key_exists('alternatives', $aChoiceInfo['sub_options'])) { - $this->ProcessWizardChoices($aChoiceInfo['sub_options']['alternatives']); + $this->ProcessWizardChoices($aChoiceInfo['sub_options']['alternatives'], $aModuleConfigs); } } $this->AddExtension($oExtension); @@ -261,6 +205,7 @@ class iTopExtensionsMap // This "new" extension is "newer" than the previous one, let's replace the previous one unset($this->aExtensions[$key]); $this->aExtensions[$oNewExtension->sCode.'/'.$oNewExtension->sVersion] = $oNewExtension; + $this->aExtensionsByCode[$oNewExtension->sCode] = $oNewExtension; return; } else { // This "new" extension is not "newer" than the previous one, let's ignore it @@ -270,6 +215,22 @@ class iTopExtensionsMap } // Finally it's not a duplicate, let's add it to the list $this->aExtensions[$oNewExtension->sCode.'/'.$oNewExtension->sVersion] = $oNewExtension; + $this->aExtensionsByCode[$oNewExtension->sCode] = $oNewExtension; + } + + public function RemoveExtension(string $sCode): void + { + $oExtension = $this->GetFromExtensionCode($sCode); + if (is_null($oExtension)) { + \IssueLog::Error(__METHOD__.": cannot find extension to remove", null, [$sCode]); + + return; + } + + \IssueLog::Debug(__METHOD__.": remove extension from map", null, [$oExtension->sCode => $oExtension->sSourceDir]); + + unset($this->aExtensions[$oExtension->sCode.'/'.$oExtension->sVersion]); + unset($this->aExtensionsByCode[$sCode]); } /** @@ -280,12 +241,28 @@ class iTopExtensionsMap */ public function GetFromExtensionCode(string $sExtensionCode): ?iTopExtension { - foreach ($this->aExtensions as $oExtension) { - if ($oExtension->sCode === $sExtensionCode) { - return $oExtension; + return $this->aExtensionsByCode[$sExtensionCode] ?? null; + } + + /** + * @param array $aExtensionCodes + * @return void + */ + public function DeclareExtensionAsRemoved(array $aExtensionCodes): void + { + $aRemovedExtension = []; + foreach ($aExtensionCodes as $sCode) { + /** @var \iTopExtension $oExtension */ + $oExtension = $this->GetFromExtensionCode($sCode); + if (!is_null($oExtension)) { + $aRemovedExtension [] = $oExtension; + \IssueLog::Debug(__METHOD__.": remove extension locally", null, ['extension_code' => $oExtension->sCode]); + } else { + \IssueLog::Warning(__METHOD__." cannot find extensions", null, ['code' => $sCode]); } } - return null; + + ModuleDiscovery::DeclareRemovedExtensions($aRemovedExtension); } /** @@ -346,19 +323,15 @@ class iTopExtensionsMap // to this extension $sModuleId = $aModuleInfo[ModuleFileReader::MODULE_INFO_ID]; list($sModuleName, $sModuleVersion) = ModuleDiscovery::GetModuleName($sModuleId); - if ($sModuleVersion == '') { - // Provide a default module version since version is mandatory when recording ExtensionInstallation - $sModuleVersion = '0.0.1'; - } $aModuleInfo[ModuleFileReader::MODULE_INFO_CONFIG]['uninstallable'] ??= 'yes'; - if (($sParentExtensionId !== null) && (array_key_exists($sParentExtensionId, $this->aExtensions)) && ($this->aExtensions[$sParentExtensionId] instanceof iTopExtension)) { - // Already inside an extension, let's add this module the list of modules belonging to this extension - $this->aExtensions[$sParentExtensionId]->aModules[] = $sModuleName; - $this->aExtensions[$sParentExtensionId]->aModuleVersion[$sModuleName] = $sModuleVersion; - $this->aExtensions[$sParentExtensionId]->aModuleInfo[$sModuleName] = $aModuleInfo[ModuleFileReader::MODULE_INFO_CONFIG]; - } else { - // Not already inside a folder containing an 'extension.xml' file + $oExtension = null; + if ($sParentExtensionId !== null) { + $oExtension = $this->aExtensions[$sParentExtensionId] ?? null; + } + + if (is_null($oExtension)) { + // Not already inside an folder containing an 'extension.xml' file // Ignore non-visible modules and auto-select ones, since these are never prompted // as a choice to the end-user @@ -382,6 +355,13 @@ class iTopExtensionsMap $oExtension->sSourceDir = $sSearchDir; $oExtension->bVisible = $bVisible; $this->AddExtension($oExtension); + } else { + $oExtension->aModules[] = $sModuleName; + $oExtension->aModuleVersion[$sModuleName] = $sModuleVersion; + $oExtension->aModuleInfo[$sModuleName] = $aModuleInfo[ModuleFileReader::MODULE_INFO_CONFIG]; + + $this->aExtensions[$sParentExtensionId] = $oExtension; + $this->aExtensionsByCode[$oExtension->sCode] = $oExtension; } closedir($hDir); @@ -400,25 +380,114 @@ class iTopExtensionsMap return false; } + /** + * Return the list of extensions found in a given directory (not recursively) + * + * @param string $sSearchDir The directory to scan + * + * @return string[]|bool + */ + public function GetExtensionsFromDir(string $sSearchDir): array|bool + { + if (!is_readable($sSearchDir)) { + return false; + } + + $aExtensions = []; + $hDir = opendir($sSearchDir); + if ($hDir !== false) { + + // Then scan the other files and subdirectories + while (($sDir = readdir($hDir)) !== false) { + if (($sDir === '.') || ($sDir === '..') || !is_dir($sSearchDir.$sDir)) { + continue; + } + + // First check if there is an extension.xml file in this directory + if (is_readable($sSearchDir.$sDir.'/extension.xml')) { + $oXml = new XMLParameters($sSearchDir.$sDir.'/extension.xml'); + $aExtensions[$oXml->Get('extension_code')] = $oXml->Get('label'); + } + } + + closedir($hDir); + } + + return $aExtensions; + } + + /** + * Read (recursively) a directory to find if it contains extensions (or modules) + * + * @param string $sSearchDir The directory to scan + * + * @return string[] list of modules + * @throws \CoreException + */ + public function GetModulesFromDir(string $sSearchDir): array + { + if (!is_readable($sSearchDir)) { + throw new CoreException("Cannot read directory: $sSearchDir"); + } + + $aModules = []; + $hDir = opendir($sSearchDir); + if ($hDir === false) { + throw new CoreException("Cannot open directory: $sSearchDir"); + } + + $aSubDirectories = []; + // Then scan the other files and subdirectories + while (($sFile = readdir($hDir)) !== false) { + if (($sFile !== '.') && ($sFile !== '..')) { + $aMatches = []; + if (is_dir($sSearchDir.'/'.$sFile)) { + // Recurse after parsing all the regular files + $aSubDirectories[] = $sSearchDir.'/'.$sFile; + } elseif (preg_match('/^module\.(.*).php$/i', $sFile)) { + // Found a module + try { + $aModuleInfo = ModuleFileReader::GetInstance()->ReadModuleFileInformation($sSearchDir.'/'.$sFile); + } catch (ModuleFileReaderException $e) { + throw new CoreException("Cannot read module file: $sFile", oPrevious: $e); + } + $sModuleId = $aModuleInfo[ModuleFileReader::MODULE_INFO_ID]; + [$sModuleName] = ModuleDiscovery::GetModuleName($sModuleId); + $aModules[$sModuleName] = $sModuleName; + } + } + } + closedir($hDir); + foreach ($aSubDirectories as $sDir) { + // Recurse inside the subdirectories + $aSubModules = $this->GetModulesFromDir($sDir); + $aModules = array_merge($aModules, $aSubModules); + } + + return $aModules; + } + /** * Check if some extension contains a module with missing dependencies... * If so, populate the aMissingDepenencies array - * @param string $sFromEnvironment + * + * @param string $sAppRoot + * * @return void + * @throws \Exception */ - protected function CheckDependencies($sFromEnvironment) + protected function CheckDependencies(string $sAppRoot) { $aSearchDirs = []; - if (is_dir(APPROOT.'/datamodels/2.x')) { - $aSearchDirs[] = APPROOT.'/datamodels/2.x'; - } elseif (is_dir(APPROOT.'/datamodels/1.x')) { - $aSearchDirs[] = APPROOT.'/datamodels/1.x'; + if (is_dir($sAppRoot.'/datamodels/2.x')) { + $aSearchDirs[] = $sAppRoot.'/datamodels/2.x'; + } elseif (is_dir($sAppRoot.'/datamodels/1.x')) { + $aSearchDirs[] = $sAppRoot.'/datamodels/1.x'; } $aSearchDirs = array_merge($aSearchDirs, $this->aScannedDirs); - try { - $aAllModules = ModuleDiscovery::GetAvailableModules($aSearchDirs, true); + ModuleDiscovery::GetModulesOrderedByDependencies($aSearchDirs, true); } catch (MissingDependencyException $e) { // Some modules have missing dependencies // Let's check what is the impact at the "extensions" level @@ -458,6 +527,65 @@ class iTopExtensionsMap return array_merge($this->aInstalledExtensions ?? [], $this->aExtensions); } + /** + * @param bool $bKeepExtensionsHavingMissingDependencies + * @param bool $bRemoteExtensionsShouldBeMandatory + * + * @return \iTopExtension[] + */ + public function GetAllExtensionsToDisplayInSetup(bool $bKeepExtensionsHavingMissingDependencies = false, bool $bRemoteExtensionsShouldBeMandatory = true): array + { + // all extensions are loaded at first screen when no installation xml: flat display + //otherwhile wizard screen displays choice screens along extension tree (cf installation.xml) + $aRes = []; + foreach ($this->GetAllExtensionsWithPreviouslyInstalled() as $oExtension) { + /** @var \iTopExtension $oExtension */ + if (! $oExtension->bVisible) { + //skip hidden extensions + continue; + } + + if ($this->bHasXmlInstallationFile && $oExtension->sSource === iTopExtension::SOURCE_WIZARD) { + //skip extensions handled in installation previous choice screens (defined in installation.xml) + continue; + } + + if (! $bKeepExtensionsHavingMissingDependencies && count($oExtension->aMissingDependencies) > 0) { + //skip extensions with dependency issues + continue; + } + + if (!$oExtension->bMandatory && $bRemoteExtensionsShouldBeMandatory) { + $oExtension->bMandatory = ($oExtension->sSource === iTopExtension::SOURCE_REMOTE); + } + $aRes[$oExtension->sCode] = $oExtension; + } + + return $aRes; + } + + public function GetAllExtensionsOptionInfo(bool $bRemoteExtensionsShouldBeMandatory = true): array + { + $aRes = []; + foreach ($this->GetAllExtensionsToDisplayInSetup(false, $bRemoteExtensionsShouldBeMandatory) as $sCode => $oExtension) { + $aRes[] = [ + 'extension_code' => $oExtension->sCode, + 'title' => $oExtension->sLabel, + 'description' => $oExtension->sDescription, + 'more_info' => $oExtension->sMoreInfoUrl, + 'default' => true, // by default offer to install all modules + 'modules' => $oExtension->aModules, + 'mandatory' => $oExtension->bMandatory, + 'source_label' => $oExtension->GetExtensionSourceLabel(), + 'uninstallable' => $oExtension->CanBeUninstalled(), + 'missing' => $oExtension->bRemovedFromDisk, + 'version' => $oExtension->sVersion, + ]; + } + + return $aRes; + } + /** * Mark the given extension as chosen * @param string $sExtensionCode The code of the extension (code without version number) @@ -466,11 +594,9 @@ class iTopExtensionsMap */ public function MarkAsChosen($sExtensionCode, $bMark = true) { - foreach ($this->aExtensions as $oExtension) { - if ($oExtension->sCode == $sExtensionCode) { - $oExtension->bMarkedAsChosen = $bMark; - break; - } + $oExtension = $this->GetFromExtensionCode($sExtensionCode); + if (!is_null($oExtension)) { + $oExtension->bMarkedAsChosen = $bMark; } } @@ -481,11 +607,11 @@ class iTopExtensionsMap */ public function IsMarkedAsChosen($sExtensionCode) { - foreach ($this->aExtensions as $oExtension) { - if ($oExtension->sCode == $sExtensionCode) { - return $oExtension->bMarkedAsChosen; - } + $oExtension = $this->GetFromExtensionCode($sExtensionCode); + if (!is_null($oExtension)) { + return $oExtension->bMarkedAsChosen; } + return false; } @@ -497,11 +623,9 @@ class iTopExtensionsMap */ protected function SetInstalledVersion($sExtensionCode, $sInstalledVersion) { - foreach ($this->aExtensions as $oExtension) { - if ($oExtension->sCode == $sExtensionCode) { - $oExtension->sInstalledVersion = $sInstalledVersion; - break; - } + $oExtension = $this->GetFromExtensionCode($sExtensionCode); + if (!is_null($oExtension)) { + $oExtension->sInstalledVersion = $sInstalledVersion; } } @@ -527,14 +651,19 @@ class iTopExtensionsMap */ public function LoadChoicesFromDatabase(Config $oConfig) { - foreach ($this->LoadInstalledExtensionsFromDatabase($oConfig) as $oExtension) { + $aLoadInstalledExtensionsFromDatabase = $this->LoadInstalledExtensionsFromDatabase($oConfig); + if (false === $aLoadInstalledExtensionsFromDatabase) { + return false; + } + + foreach ($aLoadInstalledExtensionsFromDatabase as $oExtension) { $this->MarkAsChosen($oExtension->sCode); $this->SetInstalledVersion($oExtension->sCode, $oExtension->sVersion); } return true; } - protected function LoadInstalledExtensionsFromDatabase(Config $oConfig): array|false + public function LoadInstalledExtensionsFromDatabase(Config $oConfig): array|false { try { if (CMDBSource::DBName() === null) { @@ -577,6 +706,51 @@ class iTopExtensionsMap } } + public static function GetChoicesFromDatabase(Config $oConfig): array|false + { + try { + if (CMDBSource::DBName() === null) { + CMDBSource::InitFromConfig($oConfig); + } + $sLatestInstallationDate = CMDBSource::QueryToScalar("SELECT max(installed) FROM ".$oConfig->Get('db_subname')."priv_extension_install"); + $aDBInfo = CMDBSource::QueryToArray("SELECT * FROM ".$oConfig->Get('db_subname')."priv_extension_install WHERE installed = '".$sLatestInstallationDate."'"); + + $aChoices = []; + foreach ($aDBInfo as $aExtensionInfo) { + $aChoices[] = $aExtensionInfo['code']; + } + + return $aChoices; + } catch (MySQLException $e) { + // No database or erroneous information + return false; + } + } + + /** + * Return list of extensions (ie installation choices + added - removed) +* @param string[] $aAddedExtensions +* @param string[] $aRemovedExtensions +* @return string[] : + */ + public function GetSelectedExtensions(Config $oConfig, array $aAddedExtensions, array $aRemovedExtensions): array + { + $aDbChoices = self::GetChoicesFromDatabase($oConfig); + + foreach ($aDbChoices as $i => $sChoice) { + if (in_array($sChoice, $aRemovedExtensions)) { + unset($aDbChoices[$i]); + } + } + + return array_merge($aDbChoices, $aAddedExtensions); + } + + public function GetExtraDirs(): array + { + return $this->aExtraDirs; + } + /** * Tells if the given module name is "chosen" since it is part of a "chosen" extension (in the specified source dir) * @param string $sModuleNameToFind @@ -585,8 +759,6 @@ class iTopExtensionsMap */ public function ModuleIsChosenAsPartOfAnExtension($sModuleNameToFind, $sInSourceOnly = iTopExtension::SOURCE_REMOTE) { - $bChosen = false; - foreach ($this->GetAllExtensions() as $oExtension) { if (($oExtension->sSource == $sInSourceOnly) && ($oExtension->bMarkedAsChosen == true) && diff --git a/setup/feature_removal/AbstractSetupAudit.php b/setup/feature_removal/AbstractSetupAudit.php new file mode 100644 index 0000000000..b7696546e0 --- /dev/null +++ b/setup/feature_removal/AbstractSetupAudit.php @@ -0,0 +1,113 @@ +ComputeClasses(); + + if (count($this->aRemovedClasses) == 0) { + if (count($this->aClassesBefore) == 0) { + return $this->aRemovedClasses; + } + + if (count($this->aClassesAfter) == 0) { + return $this->aRemovedClasses; + } + + $aExtensionsNames = array_diff($this->aClassesBefore, $this->aClassesAfter); + $this->aRemovedClasses = []; + $aClasses = array_values($aExtensionsNames); + sort($aClasses); + + foreach ($aClasses as $i => $sClass) { + $this->aRemovedClasses[] = $sClass; + } + } + + return $this->aRemovedClasses; + } + + /** + * Generate issues when audit detects data to remove + * + * @param bool $bStopDataCheckAtFirstIssue + * + * @return array + * @throws \CoreException + */ + public function RunDataAudit(bool $bStopDataCheckAtFirstIssue = false): array + { + $this->aFinalClassesToCleanup = []; + + foreach ($this->GetRemovedClasses() as $sClass) { + if (MetaModel::IsAbstract($sClass)) { + continue; + } + + if (!MetaModel::IsStandaloneClass($sClass)) { + $iCount = $this->Count($sClass); + $this->aFinalClassesToCleanup[$sClass] = $iCount; + if ($bStopDataCheckAtFirstIssue && $iCount > 0) { + //setup env: should raise issue ASAP + $this->LogInfoWithProperLogger("Setup audit found data to cleanup", null, $this->aFinalClassesToCleanup); + return $this->aFinalClassesToCleanup; + } + } + } + + $this->LogInfoWithProperLogger("Setup audit found data to cleanup", null, ['data_to_cleanup' => $this->aFinalClassesToCleanup]); + return $this->aFinalClassesToCleanup; + } + + public function GetDataToCleanupCount(): int + { + $res = 0; + foreach ($this->aFinalClassesToCleanup as $sClass => $iCount) { + $res += $iCount; + } + return $res; + } + + private function Count($sClass): int + { + $oSearch = DBObjectSearch::FromOQL("SELECT $sClass", []); + $oSearch->AllowAllData(); + $oSet = new DBObjectSet($oSearch); + + return $oSet->Count(); + } + + //could be shared with others in log APIs ? + private function LogInfoWithProperLogger($sMessage, $sChannel = null, $aContext = []): void + { + if (ContextTag::Check(ContextTag::TAG_SETUP)) { + SetupLog::Info($sMessage, $sChannel, $aContext); + } else { + IssueLog::Debug($sMessage, $sChannel, $aContext); + } + } +} diff --git a/setup/feature_removal/DryRemovalRuntimeEnvironment.php b/setup/feature_removal/DryRemovalRuntimeEnvironment.php new file mode 100644 index 0000000000..4cb8d1d42f --- /dev/null +++ b/setup/feature_removal/DryRemovalRuntimeEnvironment.php @@ -0,0 +1,73 @@ +aExtensionsToRemoveByCode = $aExtensionCodesToRemove; + $this->Prepare($sSourceEnv, $this->sBuildEnv); + } + + /** + * @param string $sSourceEnv + * @param string $sBuildEnv + * @return void + * @throws \MissingDependencyException + */ + private function Prepare(string $sSourceEnv, string $sBuildEnv) + { + $this->Cleanup(); + SetupUtils::copydir(APPROOT."/data/$sSourceEnv-modules", APPROOT."/data/$sBuildEnv-modules"); + SetupUtils::copydir(APPROOT."/conf/$sSourceEnv", APPROOT."/conf/$sBuildEnv"); + + $this->DeclareExtensionAsRemoved($this->aExtensionsToRemoveByCode); + } + + private function DeclareExtensionAsRemoved(array $aExtensionCodes): void + { + $oExtensionsMap = new iTopExtensionsMap($this->sBuildEnv); + $oExtensionsMap->DeclareExtensionAsRemoved($aExtensionCodes); + } + + public function Cleanup(): void + { + $sEnv = $this->sBuildEnv; + + //keep this folder empty + SetupUtils::tidydir(APPROOT."/env-$sEnv"); + + $aFolders = [ + APPROOT."/data/$sEnv-modules", + APPROOT."/data/cache-$sEnv", + APPROOT."/conf/$sEnv", + ]; + foreach ($aFolders as $sFolder) { + SetupUtils::tidydir($sFolder); + SetupUtils::rmdir_safe($sFolder); + } + + $sFiles = [ + APPROOT."/data/datamodel-$sEnv.xml", + APPROOT."/data/$sEnv.delta.prev.xml", + ]; + foreach ($sFiles as $sFile) { + if (is_file($sFile)) { + @unlink($sFile); + } + } + } +} diff --git a/setup/feature_removal/InplaceSetupAudit.php b/setup/feature_removal/InplaceSetupAudit.php new file mode 100644 index 0000000000..b49a46540a --- /dev/null +++ b/setup/feature_removal/InplaceSetupAudit.php @@ -0,0 +1,40 @@ +aClassesBefore = $aClassesBefore; + $this->sEnvAfter = $sEnvAfter; + } + + public function ComputeClasses(): void + { + if ($this->bClassesInitialized) { + return; + } + + $sCurrentEnvt = MetaModel::GetEnvironment(); + + if ($sCurrentEnvt === $this->sEnvAfter) { + $this->aClassesAfter = MetaModel::GetClasses(); + } else { + $this->aClassesAfter = ModelReflectionSerializer::GetInstance()->GetModelFromEnvironment($this->sEnvAfter); + } + + $this->bClassesInitialized = true; + } +} diff --git a/setup/feature_removal/ModelReflectionSerializer.php b/setup/feature_removal/ModelReflectionSerializer.php new file mode 100644 index 0000000000..7e858a9096 --- /dev/null +++ b/setup/feature_removal/ModelReflectionSerializer.php @@ -0,0 +1,72 @@ + $sEnv]); + + $sPHPExec = trim(utils::GetConfig()->Get('php_path')); + $sOutput = ""; + $iRes = 0; + + $sCommandLine = sprintf("$sPHPExec %s/get_model_reflection.php --env=%s", __DIR__, escapeshellarg($sEnv)); + exec($sCommandLine, $sOutput, $iRes); + if ($iRes != 0) { + $this->LogErrorWithProperLogger("Cannot get classes", null, ['env' => $sEnv, 'code' => $iRes, "output" => $sOutput, 'cmd' => $sCommandLine]); + throw new CoreException("Cannot get classes from env ".$sEnv); + } + + $aClasses = json_decode($sOutput[0] ?? null, true); + if (false === $aClasses) { + $this->LogErrorWithProperLogger("Invalid JSON", null, ['env' => $sEnv, "output" => $sOutput]); + throw new Exception("cannot get classes"); + } + + if (!is_array($aClasses)) { + $this->LogErrorWithProperLogger("not an array", null, ['env' => $sEnv, "classes" => $aClasses, "output" => $sOutput]); + throw new Exception("cannot get classes from $sEnv"); + } + + return $aClasses; + } + + //could be shared with others in log APIs ? + private function LogErrorWithProperLogger($sMessage, $sChannel = null, $aContext = []): void + { + if (ContextTag::Check(ContextTag::TAG_SETUP)) { + SetupLog::Error($sMessage, $sChannel, $aContext); + } else { + IssueLog::Error($sMessage, $sChannel, $aContext); + } + } +} diff --git a/setup/feature_removal/SetupAudit.php b/setup/feature_removal/SetupAudit.php new file mode 100644 index 0000000000..35c4628d9b --- /dev/null +++ b/setup/feature_removal/SetupAudit.php @@ -0,0 +1,57 @@ +sEnvBefore = $sEnvBefore; + $this->sEnvAfter = $sEnvAfter ?? "$sEnvBefore-build"; + } + + public function ComputeClasses(): void + { + if ($this->bClassesInitialized) { + return; + } + + $this->aClassesBefore = ModelReflectionSerializer::GetInstance()->GetModelFromEnvironment($this->sEnvBefore); + $this->aClassesAfter = ModelReflectionSerializer::GetInstance()->GetModelFromEnvironment($this->sEnvAfter); + + $this->bClassesInitialized = true; + } + + public function GetRemovedClasses(): array + { + $this->ComputeClasses(); + + if (count($this->aRemovedClasses) == 0) { + if (count($this->aClassesBefore) == 0) { + return $this->aRemovedClasses; + } + + if (count($this->aClassesAfter) == 0) { + return $this->aRemovedClasses; + } + + $aExtensionsNames = array_diff($this->aClassesBefore, $this->aClassesAfter); + $this->aRemovedClasses = []; + $aClasses = array_values($aExtensionsNames); + sort($aClasses); + + foreach ($aClasses as $i => $sClass) { + $this->aRemovedClasses[] = $sClass; + } + } + + return $this->aRemovedClasses; + } +} diff --git a/setup/feature_removal/get_model_reflection.php b/setup/feature_removal/get_model_reflection.php new file mode 100644 index 0000000000..92f99e9067 --- /dev/null +++ b/setup/feature_removal/get_model_reflection.php @@ -0,0 +1,41 @@ + $sArg) { + if (preg_match('/^--env=(.*)$/', $sArg, $aMatches)) { + $sEnv = $aMatches[1]; + } + } +} + +if (is_null($sEnv)) { + echo "No environment provided (--env) to read datamodel."; + exit(1); +} + +$sConfFile = utils::GetConfigFilePath($sEnv); + +try { + MetaModel::Startup($sConfFile, false /* $bModelOnly */, false /* $bAllowCache */, false /* $bTraceSourceFiles */, $sEnv); +} catch (\Throwable $e) { + echo $e->getMessage(); + echo $e->getTraceAsString(); + \SetupLog::Error( + "Cannot read model from provided environment", + null, + [ + 'env' => $sEnv, + 'error' => $e->getMessage(), + 'stack' => $e->getTraceAsString(), + ] + ); + echo "Cannot read model from provided environment"; + exit(1); +} + +$aClasses = MetaModel::GetClasses(); + +echo json_encode($aClasses); diff --git a/setup/itopextension.class.inc.php b/setup/itopextension.class.inc.php new file mode 100644 index 0000000000..e2d7302c0b --- /dev/null +++ b/setup/itopextension.class.inc.php @@ -0,0 +1,186 @@ +sCode = ''; + $this->sLabel = ''; + $this->sDescription = ''; + $this->sSource = self::SOURCE_WIZARD; + $this->bMandatory = false; + $this->sMoreInfoUrl = ''; + $this->bMarkedAsChosen = false; + $this->sVersion = ITOP_VERSION; + $this->sInstalledVersion = ''; + $this->aModules = []; + $this->aModuleVersion = []; + $this->aModuleInfo = []; + $this->sSourceDir = ''; + $this->bVisible = true; + $this->aMissingDependencies = []; + } + + /** + * @since 3.3.0 + * @return bool + */ + public function CanBeUninstalled(): bool + { + if (!is_null($this->bCanBeUninstalled)) { + return $this->bCanBeUninstalled; + } + foreach ($this->aModuleInfo as $sModuleCode => $aModuleInfo) { + if ($aModuleInfo['uninstallable'] !== 'yes') { + return false; + } + } + return true; + } + + public function __serialize(): array + { + return [ + 'sCode' => $this->sCode, + 'sSource' => $this->sSource, + 'sVersion' => $this->sVersion, + 'aModules' => $this->aModules, + 'aModuleVersion' => $this->aModuleVersion, + 'aModuleInfo' => $this->aModuleInfo, + ]; + } + + public function __unserialize(array $aData): void + { + $this->sCode = $aData['sCode'] ?? ''; + $this->sSource = $aData['sSource'] ?? ''; + $this->sVersion = $aData['sVersion'] ?? ''; + $this->aModules = $aData['aModules'] ?? ''; + $this->aModuleVersion = $aData['aModuleVersion'] ?? ''; + $this->aModuleInfo = $aData['aModuleInfo'] ?? ''; + } + + public function __toString(): string + { + return json_encode($this->__serialize(), JSON_PRETTY_PRINT); + } + + public function GetExtensionSourceLabel(): string + { + return match ($this->sSource) { + self::SOURCE_MANUAL => 'Local extensions folder', + self::SOURCE_REMOTE => (ITOP_APPLICATION == 'iTop') ? 'iTop Hub' : 'ITSM Designer', + self::SOURCE_WIZARD => 'iTop package', + default => '', + }; + } + + public function IsRemote(): string + { + return $this->sSource === self::SOURCE_REMOTE; + } +} diff --git a/setup/modelfactory.class.inc.php b/setup/modelfactory.class.inc.php index f53a411803..2a4dd22e84 100644 --- a/setup/modelfactory.class.inc.php +++ b/setup/modelfactory.class.inc.php @@ -308,18 +308,20 @@ class MFModule { $aDictionaries = []; foreach ([$this->sRootDir, $this->sRootDir.'/dictionaries'] as $sRootDir) { - if ($hDir = @opendir($sRootDir)) { - while (($sFile = readdir($hDir)) !== false) { - $aMatches = []; - if (preg_match( - "/^[^\\.]+.dict.".$this->sName.'.php$/i', - $sFile, - $aMatches - )) { // Dictionary files are named like .dict..php - $aDictionaries[] = $sRootDir.'/'.$sFile; + if (is_dir($sRootDir)) { + if ($hDir = @opendir($sRootDir)) { + while (($sFile = readdir($hDir)) !== false) { + $aMatches = []; + if (preg_match( + "/^[^\\.]+.dict.".$this->sName.'.php$/i', + $sFile, + $aMatches + )) { // Dictionary files are named like .dict..php + $aDictionaries[] = $sRootDir.'/'.$sFile; + } } + closedir($hDir); } - closedir($hDir); } } @@ -1071,15 +1073,23 @@ class ModelFactory */ public function LoadModule(MFModule $oModule, $aLanguages = []) { + $sRootDir = null; + $sModuleName = null; + $sModuleVersion = null; + try { - $aDataModels = $oModule->GetDataModelFiles(); + $sRootDir = $oModule->GetRootDir(); + $sModuleVersion = $oModule->GetVersion(); $sModuleName = $oModule->GetName(); + SetupLog::Debug("Loading module", null, [ $sModuleName, $sModuleVersion, $sRootDir]); + $aDataModels = $oModule->GetDataModelFiles(); + self::$aLoadedModules[] = $oModule; // For persistence in the cache $oModuleNode = $this->oDOMDocument->CreateElement('module'); $oModuleNode->setAttribute('id', $oModule->GetId()); - $oModuleNode->appendChild($this->oDOMDocument->CreateElement('root_dir', $oModule->GetRootDir())); + $oModuleNode->appendChild($this->oDOMDocument->CreateElement('root_dir', $sRootDir)); $oModuleNode->appendChild($this->oDOMDocument->CreateElement('label', $oModule->GetLabel())); $oModules = $this->oRoot->getElementsByTagName('loaded_modules')->item(0); @@ -1168,6 +1178,7 @@ class ModelFactory ]); } } catch (Exception $e) { + SetupLog::Exception("Cannot load module", $e, null, [ $sModuleName, $sModuleVersion, $sRootDir]); $aLoadedModuleNames = []; foreach (self::$aLoadedModules as $oLoadedModule) { $aLoadedModuleNames[] = $oLoadedModule->GetName().':'.$oLoadedModule->GetVersion(); @@ -1277,7 +1288,7 @@ class ModelFactory if ($bExcludeWorkspace) { $aModules = []; foreach (self::$aLoadedModules as $oModule) { - if (!$oModule instanceof MFWorkspace) { + if (!class_exists('MFWorkspace') || !$oModule instanceof MFWorkspace) { $aModules[] = $oModule; } } @@ -1801,7 +1812,7 @@ EOF */ public function FindModules() { - $aAvailableModules = ModuleDiscovery::GetAvailableModules($this->aRootDirs); + $aAvailableModules = ModuleDiscovery::GetModulesOrderedByDependencies($this->aRootDirs); $aResult = []; foreach ($aAvailableModules as $sId => $aModule) { $oModule = new MFModule($sId, $aModule['root_dir'], $aModule['label'], isset($aModule['auto_select'])); @@ -2146,8 +2157,8 @@ EOF; } /** - * Combination of AddChildNode or RedefineChildNode... it depends - * This should become the preferred way of doing things (instead of implementing a test + the call to one of the APIs! + * Combination of AddChildNode or RedefineChildNode... it depends on existing nodes + * This should become the preferred way of doing things (instead of implementing a test and the call to one of the APIs!) * * @param MFElement $oNode The node (including all subnodes) to set * @param string $sSearchId Optional Id of the node to SearchMenuNode diff --git a/setup/moduledependency/dependencyexpression.class.inc.php b/setup/moduledependency/dependencyexpression.class.inc.php index e0d166c953..33f593cd09 100644 --- a/setup/moduledependency/dependencyexpression.class.inc.php +++ b/setup/moduledependency/dependencyexpression.class.inc.php @@ -2,11 +2,9 @@ namespace Combodo\iTop\Setup\ModuleDependency; -require_once(APPROOT.'/setup/runtimeenv.class.inc.php'); - use Combodo\iTop\PhpParser\Evaluation\PhpExpressionEvaluator; -use ModuleFileReaderException; -use RunTimeEnvironment; +use Combodo\iTop\Setup\ModuleDiscovery\ModuleFileReader; +use Combodo\iTop\Setup\ModuleDiscovery\ModuleFileReaderException; /** * Class that handles a module dependency @@ -61,19 +59,19 @@ class DependencyExpression } } - private static function GetPhpExpressionEvaluator(): PhpExpressionEvaluator + public static function GetPhpExpressionEvaluator(): PhpExpressionEvaluator { - if (!isset(static::$oPhpExpressionEvaluator)) { - static::$oPhpExpressionEvaluator = new PhpExpressionEvaluator([], RunTimeEnvironment::STATIC_CALL_AUTOSELECT_WHITELIST); + if (!isset(self::$oPhpExpressionEvaluator)) { + self::$oPhpExpressionEvaluator = new PhpExpressionEvaluator([], ModuleFileReader::STATIC_CALL_AUTOSELECT_WHITELIST); } - return static::$oPhpExpressionEvaluator; + return self::$oPhpExpressionEvaluator; } /** * Return module names potentially required by current dependency * - * @return array + * @return array */ public function GetRemainingModuleNamesToResolve(): array { diff --git a/setup/moduledependency/module.class.inc.php b/setup/moduledependency/module.class.inc.php index 734c081e5d..133021208b 100644 --- a/setup/moduledependency/module.class.inc.php +++ b/setup/moduledependency/module.class.inc.php @@ -114,7 +114,7 @@ class Module } /** - * @return array: list of unique module names + * @return array list of unique module names */ public function GetUnresolvedDependencyModuleNames(): array { diff --git a/setup/moduledependency/moduledependencysort.class.inc.php b/setup/moduledependency/moduledependencysort.class.inc.php index 099167c8ac..fdded3b630 100644 --- a/setup/moduledependency/moduledependencysort.class.inc.php +++ b/setup/moduledependency/moduledependencysort.class.inc.php @@ -19,16 +19,16 @@ class ModuleDependencySort final public static function GetInstance(): ModuleDependencySort { - if (!isset(static::$oInstance)) { - static::$oInstance = new static(); + if (!isset(self::$oInstance)) { + self::$oInstance = new ModuleDependencySort(); } - return static::$oInstance; + return self::$oInstance; } final public static function SetInstance(?ModuleDependencySort $oInstance): void { - static::$oInstance = $oInstance; + self::$oInstance = $oInstance; } /** @@ -140,35 +140,34 @@ class ModuleDependencySort } //include all modules $iInDegreeCounterIncludingOutsideModules = count($oModule->GetUnresolvedDependencyModuleNames()); - $aCountDepsByModuleId[$sModuleId] = [$iInDegreeCounter, $iInDegreeCounterIncludingOutsideModules, $sModuleId]; + $aCountDepsByModuleId[$sModuleId] = new ModuleCountDepency($sModuleId, $iInDegreeCounter, $iInDegreeCounterIncludingOutsideModules); } $aRes = []; while (count($aUnresolvedDependencyModules) > 0) { asort($aCountDepsByModuleId); - uasort($aCountDepsByModuleId, function (array $aDeps1, array $aDeps2) { - //compare $iInDegreeCounter - $res = $aDeps1[0] - $aDeps2[0]; + uasort($aCountDepsByModuleId, function (ModuleCountDepency $oModuleCountDepency1, ModuleCountDepency $oModuleCountDepency2) { + $res = $oModuleCountDepency1->iInDegreeCounter - $oModuleCountDepency2->iInDegreeCounter; if ($res != 0) { return $res; } - //compare $iInDegreeCounterIncludingOutsideModules - $res = $aDeps1[1] - $aDeps2[1]; + $res = $oModuleCountDepency1->iInDegreeCounterIncludingOutsideModules - $oModuleCountDepency2->iInDegreeCounterIncludingOutsideModules; if ($res != 0) { return $res; } //alphabetical order at least - return strcmp($aDeps1[2], $aDeps2[2]); + return strcmp($oModuleCountDepency1->sModuleId, $oModuleCountDepency2->sModuleId); }); $bOneLoopAtLeast = false; - foreach ($aCountDepsByModuleId as $sModuleId => $iInDegreeCounter) { + foreach ($aCountDepsByModuleId as $sModuleId => $oModuleCountDepency) { + /** @var ModuleCountDepency $oModuleCountDepency */ $oModule = $aUnresolvedDependencyModules[$sModuleId]; - if ($bOneLoopAtLeast && $iInDegreeCounter > 0) { + if ($bOneLoopAtLeast && ($oModuleCountDepency->iInDegreeCounter > 0)) { break; } @@ -183,10 +182,10 @@ class ModuleDependencySort if (!array_key_exists($sModuleId2, $aCountDepsByModuleId)) { continue; } - $aDepCount = $aCountDepsByModuleId[$sModuleId2]; - $iInDegreeCounter = $aDepCount[0] - 1; - $iInDegreeCounterIncludingOutsideModules = $aDepCount[1]; - $aCountDepsByModuleId[$sModuleId2] = [$iInDegreeCounter, $iInDegreeCounterIncludingOutsideModules, $sModuleId2]; + /** @var ModuleCountDepency $oModuleCountDepency2 */ + $oModuleCountDepency2 = $aCountDepsByModuleId[$sModuleId2]; + $iInDegreeCounter = $oModuleCountDepency2->iInDegreeCounter - 1; + $aCountDepsByModuleId[$sModuleId2] = new ModuleCountDepency($sModuleId2, $iInDegreeCounter, $oModuleCountDepency2->iInDegreeCounterIncludingOutsideModules); } unset($aDependsOnModuleName[$oModule->GetModuleName()]); @@ -199,3 +198,18 @@ class ModuleDependencySort $aUnresolvedDependencyModules = $aRes; } } + +class ModuleCountDepency +{ + public string $sModuleId; + public int $iInDegreeCounter; + public int $iInDegreeCounterIncludingOutsideModules; + + public function __construct(string $sModuleId, int $iInDegreeCounter, int $iInDegreeCounterIncludingOutsideModules) + { + $this->iInDegreeCounter = $iInDegreeCounter; + $this->iInDegreeCounterIncludingOutsideModules = $iInDegreeCounterIncludingOutsideModules; + $this->sModuleId = $sModuleId; + } + +} diff --git a/setup/modulediscovery.class.inc.php b/setup/modulediscovery.class.inc.php index 2d2e8bb724..48422d9cdb 100755 --- a/setup/modulediscovery.class.inc.php +++ b/setup/modulediscovery.class.inc.php @@ -22,19 +22,19 @@ use Combodo\iTop\PhpParser\Evaluation\PhpExpressionEvaluator; use Combodo\iTop\Setup\ModuleDependency\Module; +use Combodo\iTop\Setup\ModuleDependency\ModuleDependencySort; use Combodo\iTop\Setup\ModuleDiscovery\ModuleFileReader; use Combodo\iTop\Setup\ModuleDiscovery\ModuleFileReaderException; require_once(APPROOT.'setup/modulediscovery/ModuleFileReader.php'); require_once(__DIR__.'/moduledependency/moduledependencysort.class.inc.php'); - -use Combodo\iTop\Setup\ModuleDependency\ModuleDependencySort; +require_once(__DIR__.'/itopextension.class.inc.php'); class MissingDependencyException extends CoreException { /** * @see \ModuleDiscovery::OrderModulesByDependencies property init - * @var array> + * @var array> * module id as key * another array as value, containing : 'module' with module info, 'dependencies' with missing dependencies */ @@ -95,6 +95,9 @@ class ModuleDiscovery protected static $m_aModules = []; protected static $m_aModuleVersionByName = []; + /** @var array<\iTopExtension> $m_aRemovedExtensions */ + protected static array $m_aRemovedExtensions = []; + // All the entries below are list of file paths relative to the module directory protected static $m_aFilesList = ['datamodel', 'webservice', 'dictionary', 'data.struct', 'data.sample']; @@ -120,10 +123,6 @@ class ModuleDiscovery if (is_null($aArgs) || ! is_array($aArgs)) { throw new ModuleFileReaderException("Error parsing module file args", 0, null, $sFilePath); } - if (!array_key_exists('itop_version', $aArgs)) { - // Assume 1.0.2 - $aArgs['itop_version'] = '1.0.2'; - } foreach (array_keys(self::$m_aModuleArgs) as $sArgName) { if (!array_key_exists($sArgName, $aArgs)) { throw new Exception("Module '$sId': missing argument '$sArgName'"); @@ -135,6 +134,10 @@ class ModuleDiscovery list($sModuleName, $sModuleVersion) = static::GetModuleName($sId); + if (self::IsModuleInExtensionList(self::$m_aRemovedExtensions, $sModuleName, $sModuleVersion, $aArgs)) { + return; + } + if (array_key_exists($sModuleName, self::$m_aModuleVersionByName)) { if (version_compare($sModuleVersion, self::$m_aModuleVersionByName[$sModuleName]['version'], '>')) { // Newer version, let's upgrade @@ -180,34 +183,21 @@ class ModuleDiscovery $sDir.'/dictionaries' => self::$m_sModulePath.'/dictionaries', ]; foreach ($aDirs as $sRootDir => $sPath) { - if ($hDir = @opendir($sRootDir)) { - while (($sFile = readdir($hDir)) !== false) { - $aMatches = []; - if (preg_match("/^[^\\.]+.dict.$sModuleName.php$/i", $sFile, $aMatches)) { // Dictionary files named like .dict..php are loaded automatically - self::$m_aModules[$sId]['dictionary'][] = $sPath.'/'.$sFile; + if (is_dir($sRootDir)) { + if ($hDir = @opendir($sRootDir)) { + while (($sFile = readdir($hDir)) !== false) { + $aMatches = []; + if (preg_match("/^[^\\.]+.dict.$sModuleName.php$/i", $sFile, $aMatches)) { // Dictionary files named like .dict..php are loaded automatically + self::$m_aModules[$sId]['dictionary'][] = $sPath.'/'.$sFile; + } } + closedir($hDir); } - closedir($hDir); } } } } - /** - * Get the list of "discovered" modules, ordered based on their (inter) dependencies - * - * @param bool $bAbortOnMissingDependency ... - * @param array $aModulesToLoad List of modules to search for, defaults to all if omitted - * - * @return array - * @throws \MissingDependencyException - */ - protected static function GetModules($bAbortOnMissingDependency = false, $aModulesToLoad = null) - { - // Order the modules to take into account their inter-dependencies - return self::OrderModulesByDependencies(self::$m_aModules, $bAbortOnMissingDependency, $aModulesToLoad); - } - /** * Arrange an list of modules, based on their (inter) dependencies * @param array $aModules The list of modules to process: 'id' => $aModuleInfo @@ -218,15 +208,20 @@ class ModuleDiscovery */ public static function OrderModulesByDependencies($aModules, $bAbortOnMissingDependency = false, $aModulesToLoad = null) { - if (is_null($aModulesToLoad)) { + if (is_null($aModulesToLoad) && count(self::$m_aRemovedExtensions) === 0) { $aFilteredModules = $aModules; } else { $aFilteredModules = []; - foreach ($aModules as $sModuleId => $aModule) { + foreach ($aModules as $sModuleId => $aModuleInfo) { $oModule = new Module($sModuleId); $sModuleName = $oModule->GetModuleName(); - if (in_array($sModuleName, $aModulesToLoad)) { - $aFilteredModules[$sModuleId] = $aModule; + + if (self::IsModuleInExtensionList(self::$m_aRemovedExtensions, $sModuleName, $oModule->GetVersion(), $aModuleInfo)) { + continue; + } + + if (is_null($aModulesToLoad) || in_array($sModuleName, $aModulesToLoad)) { + $aFilteredModules[$sModuleId] = $aModuleInfo; } } } @@ -234,27 +229,19 @@ class ModuleDiscovery return ModuleDependencySort::GetInstance()->GetModulesOrderedForInstallation($aFilteredModules, $bAbortOnMissingDependency); } - private static function GetPhpExpressionEvaluator(): PhpExpressionEvaluator + /** + * @param array<\iTopExtension> $aRemovedExtension + * @return void + */ + public static function DeclareRemovedExtensions(array $aRemovedExtension): void { - if (!isset(static::$oPhpExpressionEvaluator)) { - static::$oPhpExpressionEvaluator = new PhpExpressionEvaluator([], RunTimeEnvironment::STATIC_CALL_AUTOSELECT_WHITELIST); + if (self::$m_aRemovedExtensions != $aRemovedExtension) { + self::ResetCache(); } - - return static::$oPhpExpressionEvaluator; + self::$m_aRemovedExtensions = $aRemovedExtension; } - /** - * Search (on the disk) for all defined iTop modules, load them and returns the list (as an array) - * of the possible iTop modules to install - * - * @param $aSearchDirs array of directories to search (absolute paths) - * @param bool $bAbortOnMissingDependency ... - * @param array $aModulesToLoad List of modules to search for, defaults to all if omitted - * - * @return array A big array moduleID => ModuleData - * @throws \Exception - */ - public static function GetAvailableModules($aSearchDirs, $bAbortOnMissingDependency = false, $aModulesToLoad = null) + private static function Init($aSearchDirs): void { if (self::$m_aSearchDirs != $aSearchDirs) { self::ResetCache(); @@ -273,13 +260,60 @@ class ModuleDiscovery clearstatcache(); self::ListModuleFiles(basename($sSearchDir), dirname($sSearchDir)); } - return self::GetModules($bAbortOnMissingDependency, $aModulesToLoad); - } else { - // Reuse the previous results - return self::GetModules($bAbortOnMissingDependency, $aModulesToLoad); } } + /** + * Return all modules found on disk ordered by dependencies. Skipping modules coming from extensions declared as removed (@see ModuleDiscovery::DeclareRemovedExtensions) + * @param $aSearchDirs array of directories to search (absolute paths) + * @param bool $bAbortOnMissingDependency ... + * @param array $aModulesToLoad List of modules to search for, defaults to all if omitted + * + * @return array A big array moduleID => ModuleData + * @throws \Exception + */ + public static function GetModulesOrderedByDependencies($aSearchDirs, $bAbortOnMissingDependency = false, $aModulesToLoad = null) + { + self::Init($aSearchDirs); + + return self::OrderModulesByDependencies(self::$m_aModules, $bAbortOnMissingDependency, $aModulesToLoad); + } + + /** + * @deprecated use \ModuleDiscovery::GetModulesOrderedByDependencies instead + */ + public static function GetAvailableModules($aSearchDirs, $bAbortOnMissingDependency = false, $aModulesToLoad = null) + { + return ModuleDiscovery::GetModulesOrderedByDependencies($aSearchDirs, $bAbortOnMissingDependency, $aModulesToLoad); + } + + /** + * Return all modules found on disk (without any dependency consideration). Skipping modules coming from extensions declared as removed (@see ModuleDiscovery::DeclareRemovedExtensions) + * + * @param $aSearchDirs array of directories to search (absolute paths) + * + * @return array A big array moduleID => ModuleData + * @throws \Exception + */ + public static function GetAllModules(array $aSearchDirs): array + { + self::Init($aSearchDirs); + + $aNonRemovedModules = []; + foreach (self::$m_aModules as $sModuleId => $aModuleInfo) { + $oModule = new Module($sModuleId); + $sModuleName = $oModule->GetModuleName(); + + if (self::IsModuleInExtensionList(self::$m_aRemovedExtensions, $sModuleName, $oModule->GetVersion(), $aModuleInfo)) { + continue; + } + + $aNonRemovedModules[$sModuleId] = $aModuleInfo; + } + + return $aNonRemovedModules; + } + public static function ResetCache() { self::$m_aSearchDirs = null; @@ -289,10 +323,12 @@ class ModuleDiscovery /** * Helper function to interpret the name of a module + * * @param $sModuleId string Identifier of the module, in the form 'name/version' - * @return array(name, version) + * + * @return array of 2 elements (name, version) */ - public static function GetModuleName($sModuleId) + public static function GetModuleName($sModuleId): array { $aMatches = []; if (preg_match('!^(.*)/(.*)$!', $sModuleId, $aMatches)) { @@ -319,9 +355,11 @@ class ModuleDiscovery */ protected static function ListModuleFiles($sRelDir, $sRootDir) { - static $iDummyClassIndex = 0; $sDirectory = $sRootDir.'/'.$sRelDir; + if (!is_dir(utils::RealPath($sDirectory, APPROOT))) { + throw new Exception('Data directory ('.$sDirectory.') Does not exist or is outside iTop.'); + } if ($hDir = opendir($sDirectory)) { // This is the correct way to loop over the directory. (according to the documentation) while (($sFile = readdir($hDir)) !== false) { @@ -346,6 +384,61 @@ class ModuleDiscovery throw new Exception("Data directory (".$sDirectory.") not found or not readable."); } } + + /** + * @param array<\iTopExtension> $aExtensions + * @param string $sModuleName + * @param string $sModuleVersion + * @param array $aModuleInfo + * + * @return bool + */ + private static function IsModuleInExtensionList(array $aExtensions, string $sModuleName, string $sModuleVersion, array $aModuleInfo): bool + { + if (count($aExtensions) === 0) { + return false; + } + $aNonMatchingPaths = []; + $sModuleFilePath = $aModuleInfo[ModuleFileReader::MODULE_FILE_PATH]; + + /** @var \iTopExtension $oExtension */ + foreach ($aExtensions as $oExtension) { + $sCurrentVersion = $oExtension->aModuleVersion[$sModuleName] ?? null; + if (is_null($sCurrentVersion)) { + continue; + } + + if ($sModuleVersion !== $sCurrentVersion) { + continue; + } + + /** @var array|null $aCurrentModuleInfo */ + $aCurrentModuleInfo = $oExtension->aModuleInfo[$sModuleName] ?? null; + if (is_null($aCurrentModuleInfo)) { + SetupLog::Warning("Missing $sModuleName in ".$oExtension->sLabel.". it should not happen"); + continue; + } + + // use case: same module coming from 2 different extensions + // we remove only the one coming from removed extensions + $sCurrentModuleFilePath = $aCurrentModuleInfo[ModuleFileReader::MODULE_FILE_PATH]; + if (realpath($sModuleFilePath) !== realpath($sCurrentModuleFilePath)) { + $aNonMatchingPaths[] = $sCurrentModuleFilePath; + continue; + } + + IssueLog::Debug("Module considered as removed", null, ['extension_code' => $oExtension->sCode, 'module_name' => $sModuleName, 'module_version' => $sModuleVersion, ModuleFileReader::MODULE_FILE_PATH => $sCurrentModuleFilePath]); + return true; + } + + if (count($aNonMatchingPaths) > 0) { + //add log for support + IssueLog::Debug("Module kept as it came from non removed extensions", null, ['module_name' => $sModuleName, 'module_version' => $sModuleVersion, ModuleFileReader::MODULE_FILE_PATH => $sModuleFilePath, 'non_matching_paths' => $aNonMatchingPaths]); + } + IssueLog::Debug(__METHOD__.' Module loaded', null, ['name' => $sModuleName, 'version' => $sModuleVersion]); + return false; + } + } // End of class /** Alias for backward compatibility with old module files in which diff --git a/setup/modulediscovery/ModuleFileReader.php b/setup/modulediscovery/ModuleFileReader.php index 118f2249ac..b87df88954 100644 --- a/setup/modulediscovery/ModuleFileReader.php +++ b/setup/modulediscovery/ModuleFileReader.php @@ -7,15 +7,16 @@ use CoreException; use Exception; use ParseError; use PhpParser\Error; +use PhpParser\Node\Arg; +use PhpParser\Node\Expr\Array_; +use PhpParser\Node\Expr\Assign; use PhpParser\Node\Expr\StaticCall; +use PhpParser\Node\Scalar\String_; +use PhpParser\Node\Stmt\ElseIf_; use PhpParser\Node\Stmt\Expression; use PhpParser\Node\Stmt\If_; use PhpParser\ParserFactory; -use PhpParser\Node\Expr\Assign; -use PhpParser\Node\Stmt\ElseIf_; -use PhpParser\Node\Expr\Array_; -use PhpParser\Node\Scalar\String_; -use PhpParser\Node\Arg; +use SetupLog; require_once __DIR__.'/ModuleFileReaderException.php'; require_once APPROOT.'sources/PhpParser/Evaluation/PhpExpressionEvaluator.php'; @@ -36,11 +37,16 @@ class ModuleFileReader public const MODULE_INFO_PATH = 0; public const MODULE_INFO_ID = 1; public const MODULE_INFO_CONFIG = 2; + public const MODULE_FILE_PATH = "module_file_path"; public const STATIC_CALLWHITELIST = [ "utils::GetItopVersionWikiSyntax", ]; + public const STATIC_CALL_AUTOSELECT_WHITELIST = [ + "SetupInfo::ModuleIsSelected", + ]; + protected function __construct() { $this->oPhpExpressionEvaluator = new PhpExpressionEvaluator(static::FUNC_CALL_WHITELIST, static::STATIC_CALLWHITELIST); @@ -48,21 +54,23 @@ class ModuleFileReader final public static function GetInstance(): ModuleFileReader { - if (!isset(static::$oInstance)) { - static::$oInstance = new static(); + if (!isset(self::$oInstance)) { + self::$oInstance = new ModuleFileReader(); } - return static::$oInstance; + return self::$oInstance; } final public static function SetInstance(?ModuleFileReader $oInstance): void { - static::$oInstance = $oInstance; + self::$oInstance = $oInstance; } /** * Read the information from a module file (module.xxx.php) - * @param string $sModuleFile + * + * @param string $sModuleFilePath + * * @return array * @throws ModuleFileReaderException */ @@ -108,7 +116,9 @@ class ModuleFileReader * Read the information from a module file (module.xxx.php) * Warning: this method is using eval() function to load the ModuleInstallerAPI classes. * Current method is never called at design/runtime. It is acceptable to use it during setup only. - * @param string $sModuleFile + * + * @param string $sModuleFilePath + * * @return array * @throws ModuleFileReaderException */ @@ -134,6 +144,7 @@ class ModuleFileReader } // Replace the main function call by an assignment to a variable, as an array... $sModuleFileContents = str_replace(['SetupWebPage::AddModule', 'ModuleDiscovery::AddModule'], '$aModuleInfo = array', $sModuleFileContents); + SetupLog::Debug(__METHOD__, null, ['module_file' => $sModuleFilePath]); eval($sModuleFileContents); // Assigns $aModuleInfo if (count($aModuleInfo) === 0) { @@ -164,7 +175,7 @@ class ModuleFileReader private function CompleteModuleInfoWithFilePath(array &$aModuleInfo) { if (count($aModuleInfo) == 3) { - $aModuleInfo[static::MODULE_INFO_CONFIG]['module_file_path'] = $aModuleInfo[static::MODULE_INFO_PATH]; + $aModuleInfo[static::MODULE_INFO_CONFIG][self::MODULE_FILE_PATH] = $aModuleInfo[static::MODULE_INFO_PATH]; } } @@ -175,15 +186,21 @@ class ModuleFileReader } $sModuleInstallerClass = $aModuleInfo['installer']; + if (strlen($sModuleInstallerClass) === 0) { + return null; + } + if (!class_exists($sModuleInstallerClass)) { - $sModuleFilePath = $aModuleInfo['module_file_path']; + $sModuleFilePath = $aModuleInfo[self::MODULE_FILE_PATH]; $this->ReadModuleFileInformationUnsafe($sModuleFilePath); } if (!class_exists($sModuleInstallerClass)) { + \IssueLog::Error(__METHOD__, null, $aModuleInfo); throw new CoreException("Wrong installer class: '$sModuleInstallerClass' is not a PHP class - Module: ".$aModuleInfo['label']); } if (!is_subclass_of($sModuleInstallerClass, 'ModuleInstallerAPI')) { + \IssueLog::Error(__METHOD__, null, $aModuleInfo); throw new CoreException("Wrong installer class: '$sModuleInstallerClass' is not derived from 'ModuleInstallerAPI' - Module: ".$aModuleInfo['label']); } @@ -192,7 +209,7 @@ class ModuleFileReader /** * @param string $sModuleFilePath - * @param \PhpParser\Node\Expr\Assign $oAssignation + * @param \PhpParser\Node\Stmt\Expression $oExpression * * @return array|null * @throws ModuleFileReaderException diff --git a/setup/moduleinstallation/AnalyzeInstallation.php b/setup/moduleinstallation/AnalyzeInstallation.php new file mode 100644 index 0000000000..6a30e6edf6 --- /dev/null +++ b/setup/moduleinstallation/AnalyzeInstallation.php @@ -0,0 +1,130 @@ + + * 'iTop' => array( + * 'installed_version' => ... (could be empty in case of a fresh install) + * 'available_version => ... + * ) + * => array( + * 'installed_version' => ... + * 'available_version' => ... + * 'install' => array( + * 'flag' => SETUP_NEVER | SETUP_OPTIONAL | SETUP_MANDATORY + * 'message' => ... + * ) + * 'uninstall' => array( + * 'flag' => SETUP_NEVER | SETUP_OPTIONAL | SETUP_MANDATORY + * 'message' => ... + * ) + * 'label' => ... + * 'dependencies' => array(, , ...) + * 'visible' => true | false + * ) + * ) + * @throws \Exception + */ + + public function AnalyzeInstallation(?Config $oConfig, mixed $modulesPath, bool $bAbortOnMissingDependency = false, ?array $aModulesToLoad = null) + { + $aRes = [ + ROOT_MODULE => [ + 'installed_version' => '', + 'available_version' => ITOP_VERSION_FULL, + 'name_code' => ITOP_APPLICATION, + ], + ]; + + $aDirs = is_array($modulesPath) ? $modulesPath : [$modulesPath]; + if (! is_null($this->aAvailableModules)) { + //test only + $aAvailableModules = $this->aAvailableModules; + } else { + $aAvailableModules = ModuleDiscovery::GetModulesOrderedByDependencies($aDirs, $bAbortOnMissingDependency, $aModulesToLoad); + } + + foreach ($aAvailableModules as $sModuleId => $aModuleInfo) { + list($sModuleName, $sModuleVersion) = ModuleDiscovery::GetModuleName($sModuleId); + + $aModuleInfo['installed_version'] = ''; + $aModuleInfo['available_version'] = $sModuleVersion; + + if ($aModuleInfo['mandatory']) { + $aModuleInfo['install'] = [ + 'flag' => MODULE_ACTION_MANDATORY, + 'message' => 'the module is part of the application', + ]; + } else { + $aModuleInfo['install'] = [ + 'flag' => MODULE_ACTION_OPTIONAL, + 'message' => '', + ]; + } + $aRes[$sModuleName] = $aModuleInfo; + } + + $aCurrentlyInstalledModules = ModuleInstallationRepository::GetInstance()->ReadComputeInstalledModules($oConfig); + + // Adjust the list of proposed modules + foreach ($aCurrentlyInstalledModules as $sModuleName => $aModuleDB) { + if ($sModuleName == ROOT_MODULE) { + $aRes[$sModuleName]['installed_version'] = $aModuleDB['version']; + continue; + } + + if (!array_key_exists($sModuleName, $aRes)) { + // A module was installed, it is not proposed in the new build... skip + continue; + } + + $aRes[$sModuleName]['installed_version'] = $aModuleDB['version']; + + if ($aRes[$sModuleName]['mandatory']) { + $aRes[$sModuleName]['uninstall'] = [ + 'flag' => MODULE_ACTION_IMPOSSIBLE, + 'message' => 'the module is part of the application', + ]; + } else { + $aRes[$sModuleName]['uninstall'] = [ + 'flag' => MODULE_ACTION_OPTIONAL, + 'message' => '', + ]; + } + } + + return $aRes; + } +} diff --git a/setup/moduleinstallation/InstallationChoicesToModuleConverter.php b/setup/moduleinstallation/InstallationChoicesToModuleConverter.php new file mode 100644 index 0000000000..991431e27d --- /dev/null +++ b/setup/moduleinstallation/InstallationChoicesToModuleConverter.php @@ -0,0 +1,249 @@ + $aInstallationChoices + * @param array $aSearchDirs + * @param string|null $sInstallationFilePath + * @param array|null $aExtensionDirs : module/extension dirs to load if they are compliant with choices + * + * @return array + * @throws \ModuleInstallationException + */ + public function GetModules(array $aInstallationChoices, array $aSearchDirs, ?string $sInstallationFilePath = null, ?array $aExtensionDirs = null): array + { + $aPackageModules = $this->GetAllModules($aSearchDirs); + + $bInstallationFileProvided = ! is_null($sInstallationFilePath) && is_file($sInstallationFilePath); + + if ($bInstallationFileProvided) { + $oXMLParameters = new XMLParameters($sInstallationFilePath); + $aSteps = $oXMLParameters->Get('steps', []); + if (!is_array($aSteps)) { + return []; + } + $aInstalledModuleNames = $this->FindInstalledPackageModules($aPackageModules, $aInstallationChoices, $aSteps); + } else { + $aInstalledModuleNames = $this->FindInstalledPackageModules($aPackageModules, $aInstallationChoices); + } + + $aInstalledModules = []; + foreach (array_keys($aPackageModules) as $sModuleId) { + list($sModuleName) = ModuleDiscovery::GetModuleName($sModuleId); + if (in_array($sModuleName, $aInstalledModuleNames)) { + $aInstalledModules[$sModuleName] = $sModuleId; + } + } + + if (!is_null($aExtensionDirs)) { + foreach (array_keys($this->GetAllModules($aExtensionDirs)) as $sModuleId) { + $oModule = new Module($sModuleId); + + $sPreviousModuleId = $aInstalledModules[$oModule->GetModuleName()] ?? null; + if (is_null($sPreviousModuleId)) { + $aInstalledModules[$oModule->GetModuleName()] = $sModuleId; + continue; + } + + $oPreviousModule = new Module($sPreviousModuleId); + if (version_compare($oModule->GetVersion(), $oPreviousModule->GetVersion(), '>')) { + $aInstalledModules[$oModule->GetModuleName()] = $sModuleId; + } + } + } + + return array_values($aInstalledModules); + } + + /** + * Provide all modules used to compute in @see GetModules() + * + * @param $aSearchDirs array of directories to search (absolute paths) + * + * @return array A big array moduleID => ModuleData + * @throws \Exception + */ + protected function GetAllModules(array $aSearchDirs): array + { + + return ModuleDiscovery::GetAllModules($aSearchDirs); + } + + private function FindInstalledPackageModules(array $aPackageModules, array $aInstallationChoices, ?array $aInstallationDescription = null): array + { + $aInstalledModules = []; + + $this->ProcessDefaultModules($aPackageModules, $aInstalledModules); + + if (is_null($aInstallationDescription)) { + //in legacy usecase: choices are flat modules list already + foreach ($aInstallationChoices as $sModuleName) { + $aInstalledModules[$sModuleName] = true; + } + } else { + $this->GetModuleNamesFromInstallationChoices($aInstallationChoices, $aInstallationDescription, $aInstalledModules); + } + + $this->ProcessAutoSelectModules($aPackageModules, $aInstalledModules); + + return array_keys($aInstalledModules); + } + + private function IsDefaultModule(string $sModuleId, array $aModule): bool + { + if (($sModuleId === ROOT_MODULE)) { + return false; + } + + if (isset($aModule['auto_select'])) { + return false; + } + + if ($aModule['category'] === 'authentication') { + return true; + } + + return !$aModule['visible']; + } + + private function ProcessDefaultModules(array &$aPackageModules, array &$aInstalledModules): void + { + foreach ($aPackageModules as $sModuleId => $aModule) { + if ($this->IsDefaultModule($sModuleId, $aModule)) { + list($sModuleName) = ModuleDiscovery::GetModuleName($sModuleId); + $aInstalledModules[$sModuleName] = true; + unset($aPackageModules[$sModuleId]); + } + } + } + + private function IsAutoSelectedModule(array $aInstalledModules, string $sModuleId, array $aModule): bool + { + if (($sModuleId === ROOT_MODULE)) { + return false; + } + + if (!isset($aModule['auto_select'])) { + return false; + } + + try { + SetupInfo::SetSelectedModules($aInstalledModules); + return DependencyExpression::GetPhpExpressionEvaluator()->ParseAndEvaluateBooleanExpression($aModule['auto_select']); + } catch (Exception $e) { + IssueLog::Error('Error evaluating module auto-select', null, [ + 'module' => $sModuleId, + 'error' => $e->getMessage(), + 'evaluated code' => $aModule['auto_select'], + 'stacktrace' => $e->getTraceAsString(), + ]); + } + + return false; + } + + private function ProcessAutoSelectModules(array $aPackageModules, array &$aInstalledModules): void + { + foreach ($aPackageModules as $sModuleId => $aModule) { + if ($this->IsAutoSelectedModule($aInstalledModules, $sModuleId, $aModule)) { + list($sModuleName) = ModuleDiscovery::GetModuleName($sModuleId); + $aInstalledModules[$sModuleName] = true; + } + } + } + + private function GetModuleNamesFromInstallationChoices(array $aInstallationChoices, array $aInstallationDescription, array &$aModuleNames): void + { + foreach ($aInstallationDescription as $aStepInfo) { + $aOptions = $aStepInfo['options'] ?? null; + if (is_array($aOptions)) { + foreach ($aOptions as $aChoiceInfo) { + $this->ProcessSelectedChoice($aInstallationChoices, $aChoiceInfo, $aModuleNames); + } + } + $aOptions = $aStepInfo['alternatives'] ?? null; + if (is_array($aOptions)) { + foreach ($aOptions as $aChoiceInfo) { + $this->ProcessSelectedChoice($aInstallationChoices, $aChoiceInfo, $aModuleNames); + } + } + } + } + + private function ProcessSelectedChoice(array $aInstallationChoices, array $aChoiceInfo, array &$aInstalledModules) + { + if (!is_array($aChoiceInfo)) { + return; + } + + $sMandatory = $aChoiceInfo['mandatory'] ?? 'false'; + + $aCurrentModules = $aChoiceInfo['modules'] ?? []; + $sExtensionCode = $aChoiceInfo['extension_code']; + + $bSelected = ($sMandatory === 'true') || in_array($sExtensionCode, $aInstallationChoices); + + if (!$bSelected) { + return; + } + + foreach ($aCurrentModules as $sModuleId) { + $aInstalledModules[$sModuleId] = true; + } + + $aAlternatives = $aChoiceInfo['alternatives'] ?? null; + if (is_array($aAlternatives)) { + foreach ($aAlternatives as $aSubChoiceInfo) { + $this->ProcessSelectedChoice($aInstallationChoices, $aSubChoiceInfo, $aInstalledModules); + } + } + + $aSubOptionsChoiceInfo = $aChoiceInfo['sub_options'] ?? null; + if (is_array($aSubOptionsChoiceInfo)) { + $aSubOptions = $aSubOptionsChoiceInfo['options'] ?? null; + if (is_array($aSubOptions)) { + foreach ($aSubOptions as $aSubChoiceInfo) { + $this->ProcessSelectedChoice($aInstallationChoices, $aSubChoiceInfo, $aInstalledModules); + } + } + $aSubAlternatives = $aSubOptionsChoiceInfo['alternatives'] ?? null; + if (is_array($aSubAlternatives)) { + foreach ($aSubAlternatives as $aSubChoiceInfo) { + $this->ProcessSelectedChoice($aInstallationChoices, $aSubChoiceInfo, $aInstalledModules); + } + } + } + } +} diff --git a/setup/moduleinstallation/ModuleInstallationException.php b/setup/moduleinstallation/ModuleInstallationException.php new file mode 100644 index 0000000000..40fdccc831 --- /dev/null +++ b/setup/moduleinstallation/ModuleInstallationException.php @@ -0,0 +1,5 @@ +ReadFromDB($oConfig); + } catch (MySQLException $e) { + // No database or erroneous information + } + + return $this->ComputeInstalledModules($aSelectInstall); + } + + /** +* @param \Config|null $oConfig +* @return array +* @throws \MySQLException +* @throws \MySQLQueryHasNoResultException + */ + public function ReadFromDB(?Config $oConfig): array + { + if (is_null($oConfig)) { + return []; + } + + if (! is_null($this->aSelectInstall)) { + //test only + return $this->aSelectInstall; + } + + CMDBSource::InitFromConfig($oConfig); + //read db module installations + $tableWithPrefix = $this->GetTableWithPrefix($oConfig); + $iRootId = CMDBSource::QueryToScalar("SELECT max(parent_id) FROM $tableWithPrefix"); + // Get the latest installed modules, without the "root" ones (iTop version and datamodel version) + $sSQL = <<Get('db_subname'); + if (utils::IsNullOrEmptyString($sPrefix)) { + return "priv_module_install"; + } + + return "{$sPrefix}priv_module_install"; + } + + /** + * @param \Config $oConfig + * + * @return array|false + */ + public function GetApplicationVersion(Config $oConfig) + { + try { + CMDBSource::InitFromConfig($oConfig); + $tableWithPrefix = $this->GetTableWithPrefix($oConfig); + $sSQLQuery = "SELECT * FROM $tableWithPrefix"; + $aSelectInstall = CMDBSource::QueryToArray($sSQLQuery); + } catch (MySQLException $e) { + // No database or erroneous information + SetupLog::Error( + 'Can not connect to the database', + null, + [ + 'host' => $oConfig->Get('db_host'), + 'user' => $oConfig->Get('db_user'), + 'pwd:' => $oConfig->Get('db_pwd'), + 'db name' => $oConfig->Get('db_name'), + 'msg' => $e->getMessage(), + ] + ); + return false; + } + + $aResult = []; + // Scan the list of installed modules to get the version of the 'ROOT' module which holds the main application version + foreach ($aSelectInstall as $aInstall) { + $sModuleVersion = $aInstall['version']; + if ($sModuleVersion == '') { + // Though the version cannot be empty in iTop 2.0, it used to be possible + // therefore we have to put something here or the module will not be considered + // as being installed + $sModuleVersion = '0.0.0'; + } + + if ($aInstall['parent_id'] == 0) { + if ($aInstall['name'] == DATAMODEL_MODULE) { + $aResult['datamodel_version'] = $sModuleVersion; + $aComments = json_decode($aInstall['comment'], true); + if (is_array($aComments)) { + $aResult = array_merge($aResult, $aComments); + } + } else { + $aResult['product_name'] = $aInstall['name']; + $aResult['product_version'] = $sModuleVersion; + } + } + } + if (!array_key_exists('datamodel_version', $aResult)) { + // Versions prior to 2.0 did not record the version of the datamodel + // so assume that the datamodel version is equal to the application version + $aResult['datamodel_version'] = $aResult['product_version']; + } + + SetupLog::Info(__METHOD__, null, ["product_name" => $aResult['product_name'], "product_version" => $aResult['product_version']]); + + return count($aResult) == 0 ? false : $aResult; + } + + private function ComputeInstalledModules(array $aSelectInstall): array + { + $aInstallByModule = []; // array of => array ('installed' => timestamp, 'version' => ) + + //module installation datetime is mostly the same for all modules + //unless there was issue recording things in DB + $sFirstDatetime = null; + $iFirstTime = -1; + foreach ($aSelectInstall as $aInstall) { + //$aInstall['comment']; // unsused + $sDatetime = $aInstall['installed']; + + if (is_null($sFirstDatetime)) { + $sFirstDatetime = $sDatetime; + $iFirstTime = strtotime($sDatetime); + $iInstalled = $iFirstTime; + } elseif ($sDatetime === $sFirstDatetime) { + $iInstalled = $iFirstTime; + } else { + $sDatetime = $aInstall['installed']; + $iInstalled = strtotime($sDatetime); + } + + $sModuleName = $aInstall['name']; + $sModuleVersion = $aInstall['version']; + if ($sModuleVersion == '') { + // Though the version cannot be empty in iTop 2.0, it used to be possible + // therefore we have to put something here or the module will not be considered + // as being installed + $sModuleVersion = '0.0.0'; + } + + if ($aInstall['parent_id'] == 0) { + $aInstallByModule[ROOT_MODULE] = [ + 'installed_version' => $sModuleVersion, + 'installed' => $iInstalled, + 'version' => $sModuleVersion, + ]; + } else { + $aInstallByModule[$sModuleName] = [ + 'installed' => $iInstalled, + 'version' => $sModuleVersion, + ]; + } + } + + return $aInstallByModule; + } + + /** + * Return previous module installation. offset is applied on parent_id. + * @param $iOffset: by default (offset=0) returns current installation + * @return array + */ + public static function GetPreviousModuleInstallationsByOffset(int $iOffset = 0): array + { + $oFilter = DBObjectSearch::FromOQL('SELECT ModuleInstallation AS mi WHERE mi.parent_id=0 AND mi.name!="datamodel"'); + $oSet = new DBObjectSet($oFilter, ['installed' => false]); // Most recent first + $oSet->SetLimit($iOffset + 1); + + $iParentId = 0; + while (!is_null($oModuleInstallation = $oSet->Fetch())) { + /** @var \DBObject $oModuleInstallation */ + if ($iOffset == 0) { + $iParentId = $oModuleInstallation->Get('id'); + break; + } + $iOffset--; + } + + if ($iParentId === 0) { + IssueLog::Error("no ITOP_APPLICATION ModuleInstallation found", null, ['offset' => $iOffset]); + throw new \Exception("no ITOP_APPLICATION ModuleInstallation found"); + } + + $oFilter = DBObjectSearch::FromOQL("SELECT ModuleInstallation AS mi WHERE mi.id=$iParentId OR mi.parent_id=$iParentId"); + $oSet = new DBObjectSet($oFilter); // Most recent first + $aRawValues = $oSet->ToArrayOfValues(); + $aValues = []; + foreach ($aRawValues as $aRawValue) { + $aValue = []; + foreach ($aRawValue as $sAliasAttCode => $sValue) { + // remove 'mi.' from AttCode + $sAttCode = substr($sAliasAttCode, 3); + $aValue[$sAttCode] = $sValue; + } + + $aValues[] = $aValue; + } + return $aValues; + } +} diff --git a/setup/moduleinstallation.class.inc.php b/setup/moduleinstallation/moduleinstallation.class.inc.php similarity index 100% rename from setup/moduleinstallation.class.inc.php rename to setup/moduleinstallation/moduleinstallation.class.inc.php diff --git a/setup/moduleinstaller.class.inc.php b/setup/moduleinstaller.class.inc.php index 4af241f1c2..aff6a1c1fb 100644 --- a/setup/moduleinstaller.class.inc.php +++ b/setup/moduleinstaller.class.inc.php @@ -17,8 +17,6 @@ // You should have received a copy of the GNU Affero General Public License // along with iTop. If not, see -require_once(APPROOT.'setup/setuppage.class.inc.php'); - /** * Class ModuleInstaller * Defines the API to implement module specific actions during the setup @@ -130,6 +128,7 @@ abstract class ModuleInstallerAPI if (in_array($sTo, $aNewValues)) { $sEnumCol = $oAttDef->Get("sql"); $aFields = CMDBSource::QueryToArray("SHOW COLUMNS FROM `$sTableName` WHERE Field = '$sEnumCol'"); + $aCurrentValues = []; if (isset($aFields[0]['Type'])) { $sColType = $aFields[0]['Type']; // Note: the parsing should rely on str_getcsv (requires PHP 5.3) to cope with escaped string diff --git a/setup/parameters.class.inc.php b/setup/parameters.class.inc.php index 40680a2da8..3426341c82 100644 --- a/setup/parameters.class.inc.php +++ b/setup/parameters.class.inc.php @@ -7,6 +7,7 @@ class InvalidParameterException extends Exception abstract class Parameters { public $aData = null; + private ?array $aParamValues = null; public function __construct() { @@ -26,24 +27,26 @@ abstract class Parameters */ public function GetParamForConfigArray() { - $aDBParams = $this->Get('database'); - $aParamValues = [ - 'mode' => $this->Get('mode'), - 'db_server' => $aDBParams['server'], - 'db_user' => $aDBParams['user'], - 'db_pwd' => $aDBParams['pwd'], - 'db_name' => $aDBParams['name'], - 'new_db_name' => $aDBParams['name'], - 'db_prefix' => $aDBParams['prefix'], - 'db_tls_enabled' => $aDBParams['db_tls_enabled'], - 'db_tls_ca' => $aDBParams['db_tls_ca'], - 'application_path' => $this->Get('url', ''), - 'language' => $this->Get('language', ''), - 'graphviz_path' => $this->Get('graphviz_path', ''), - 'source_dir' => $this->Get('source_dir', ''), - ]; + if (is_null($this->aParamValues)) { + $aDBParams = $this->Get('database'); + $this->aParamValues = [ + 'mode' => $this->Get('mode'), + 'db_server' => $aDBParams['server'], + 'db_user' => $aDBParams['user'], + 'db_pwd' => $aDBParams['pwd'], + 'db_name' => $aDBParams['name'], + 'new_db_name' => $aDBParams['name'], + 'db_prefix' => $aDBParams['prefix'], + 'db_tls_enabled' => $aDBParams['db_tls_enabled'], + 'db_tls_ca' => $aDBParams['db_tls_ca'], + 'application_path' => $this->Get('url', ''), + 'language' => $this->Get('language', ''), + 'graphviz_path' => $this->Get('graphviz_path', ''), + 'source_dir' => $this->Get('source_dir', ''), + ]; + } - return $aParamValues; + return $this->aParamValues; } public function Set($sCode, $value) @@ -104,7 +107,9 @@ class PHPParameters extends Parameters { if ($this->aData == null) { require_once($sParametersFile); - $this->aData = $ITOP_PARAMS; // Defined in the file loaded just above + if (isset($ITOP_PARAMS)) { + $this->aData = $ITOP_PARAMS; // Defined in the file loaded just above + } } } } diff --git a/setup/runtimeenv.class.inc.php b/setup/runtimeenv.class.inc.php index b88e3aea92..ec28de9b56 100644 --- a/setup/runtimeenv.class.inc.php +++ b/setup/runtimeenv.class.inc.php @@ -25,6 +25,8 @@ */ use Combodo\iTop\PhpParser\Evaluation\PhpExpressionEvaluator; +use Combodo\iTop\Setup\FeatureRemoval\SetupAudit; +use Combodo\iTop\Setup\ModuleDependency\Module; use Combodo\iTop\Setup\ModuleDiscovery\ModuleFileReader; use Combodo\iTop\Setup\ModuleDiscovery\ModuleFileReaderException; @@ -32,6 +34,9 @@ require_once APPROOT."setup/modulediscovery.class.inc.php"; require_once APPROOT.'setup/modelfactory.class.inc.php'; require_once APPROOT.'setup/compiler.class.inc.php'; require_once APPROOT.'setup/extensionsmap.class.inc.php'; +require_once APPROOT.'setup/moduleinstallation/AnalyzeInstallation.php'; +require_once APPROOT.'/setup/moduleinstallation/InstallationChoicesToModuleConverter.php'; +require_once APPROOT.'/setup/moduleinstallation/moduleinstallation.class.inc.php'; define('MODULE_ACTION_OPTIONAL', 1); define('MODULE_ACTION_MANDATORY', 2); @@ -41,9 +46,7 @@ define('DATAMODEL_MODULE', 'datamodel'); // Convention to store the version of t class RunTimeEnvironment { - public const STATIC_CALL_AUTOSELECT_WHITELIST = [ - "SetupInfo::ModuleIsSelected", - ]; + private static bool $bMetamodelStarted = false; /** * The name of the environment that the caller wants to build @@ -53,42 +56,68 @@ class RunTimeEnvironment /** * Environment into which the build will be performed - * @var string sTargetEnv + * @var string sBuildEnv */ - protected $sTargetEnv; + protected $sBuildEnv; /** * Extensions map of the source environment * @var iTopExtensionsMap */ - protected $oExtensionsMap; + protected ?iTopExtensionsMap $oExtensionsMap; + + protected function GetExtensionMap(): ?iTopExtensionsMap + { + return $this->oExtensionsMap; + } + + public function InitExtensionMap($aExtraDirs, $oSourceConfig) + { + // Actually read the modules available for the build environment, + // but get the selection from the source environment and finally + // mark as (automatically) chosen all the "remote" modules present in the + // build environment (data/-modules) + // The actual choices will be recorded by RecordInstallation below + $this->oExtensionsMap = new iTopExtensionsMap($this->sBuildEnv, $aExtraDirs); + $this->oExtensionsMap->LoadChoicesFromDatabase($oSourceConfig); + } /** * Toolset for building a run-time environment * * @param string $sEnvironment (e.g. 'test') - * @param bool $bAutoCommit (make the target environment directly, or build a temporary one) + * @param bool $bAutoCommit (make the final environment directly, or build a temporary one) */ - public function __construct($sEnvironment = 'production', $bAutoCommit = true) + public function __construct($sEnvironment = ITOP_DEFAULT_ENV, $bAutoCommit = true) { $this->sFinalEnv = $sEnvironment; if ($bAutoCommit) { // Build directly onto the requested environment - $this->sTargetEnv = $sEnvironment; + $this->sBuildEnv = $sEnvironment; } else { - // Build into a temporary target - $this->sTargetEnv = $sEnvironment.'-build'; + // Build into a temporary dir + $this->sBuildEnv = $sEnvironment.'-build'; } $this->oExtensionsMap = null; + SetupLog::Enable(APPROOT.'log/setup.log'); } /** * Return the full path to the compiled code (do not use after commit) * @return string */ - public function GetBuildDir() + public function GetBuildDir(): string { - return APPROOT.'env-'.$this->sTargetEnv; + return APPROOT.'env-'.$this->sBuildEnv; + } + + /** + * Return the full path to the compiled code (do not use after commit) + * @return string + */ + public function GetBuildEnv(): string + { + return $this->sBuildEnv; } /** @@ -107,14 +136,17 @@ class RunTimeEnvironment /** * Helper function to initialize the ORM and load the data model * from the given file + * * @param $oConfig object The configuration (volatile, not necessarily already on disk) * @param $bModelOnly boolean Whether or not to allow loading a data model with no corresponding DB - * @return none + * @param bool $bUseCache + * + * @throws \CoreException + * @throws \DictExceptionUnknownLanguage + * @throws \MySQLException */ - public function InitDataModel($oConfig, $bModelOnly = true, $bUseCache = false) + public function InitDataModel($oConfig, $bModelOnly = true, $bUseCache = false): void { - require_once APPROOT.'/setup/moduleinstallation.class.inc.php'; - $sConfigFile = $oConfig->GetLoadedFile(); if (strlen($sConfigFile) > 0) { $this->log_info("MetaModel::Startup from $sConfigFile (ModelOnly = $bModelOnly)"); @@ -124,20 +156,166 @@ class RunTimeEnvironment if (!$bUseCache) { // Reset the cache for the first use ! - MetaModel::ResetAllCaches($this->sTargetEnv); + MetaModel::ResetAllCaches($this->sBuildEnv); } - MetaModel::Startup($oConfig, $bModelOnly, $bUseCache, false /* $bTraceSourceFiles */, $this->sTargetEnv); + if (! isset($_SESSION)) { + //used in all UI setups (not unattended) + session_start(); + } + $_SESSION['itop_env'] = $this->sBuildEnv; + + MetaModel::Startup($oConfig, $bModelOnly, $bUseCache, false, $this->sBuildEnv); if ($this->oExtensionsMap === null) { - $this->oExtensionsMap = new iTopExtensionsMap($this->sTargetEnv); + $this->oExtensionsMap = new iTopExtensionsMap($this->sBuildEnv); + } + } + + /** + * @param string $sMode + * @param \Config $oConfig + * + * @throws \CoreException + * @throws \MySQLException + * @throws \MySQLHasGoneAwayException + */ + public function MigrateDataBeforeUpdateStructure(string $sMode, Config $oConfig): void + { + $this->InitDataModel($oConfig); + $sDBName = $oConfig->Get('db_name'); + $sDBPrefix = $oConfig->Get('db_subname'); + + // In 2.6.0 the 'fields' attribute has been moved from Query to QueryOQL for dependencies reasons + ModuleInstallerAPI::MoveColumnInDB($sDBPrefix.'priv_query', 'fields', $sDBPrefix.'priv_query_oql', 'fields'); + + // Migrate application data format + // + // priv_internalUser caused troubles because MySQL transforms table names to lower case under Windows + // This becomes an issue when moving your installation data to/from Windows + // Starting 2.0, all table names must be lowercase + if ($sMode != 'install') { + SetupLog::Info("Renaming '{$sDBPrefix}priv_internalUser' into '{$sDBPrefix}priv_internaluser' (lowercase)"); + // This command will have no effect under Windows... + // and it has been written in two steps so as to make it work under windows! + CMDBSource::SelectDB($sDBName); + try { + $sRepair = "RENAME TABLE `{$sDBPrefix}priv_internalUser` TO `{$sDBPrefix}priv_internaluser_other`, `{$sDBPrefix}priv_internaluser_other` TO `{$sDBPrefix}priv_internaluser`"; + CMDBSource::Query($sRepair); + } catch (Exception $e) { + SetupLog::Info("Renaming '{$sDBPrefix}priv_internalUser' failed (already done in a previous upgrade?)"); + } + + // let's remove the records in priv_change which have no counterpart in priv_changeop + SetupLog::Info("Cleanup of '{$sDBPrefix}priv_change' to remove orphan records"); + CMDBSource::SelectDB($sDBName); + try { + $sTotalCount = "SELECT COUNT(*) FROM `{$sDBPrefix}priv_change`"; + $iTotalCount = (int)CMDBSource::QueryToScalar($sTotalCount); + SetupLog::Info("There is a total of $iTotalCount records in {$sDBPrefix}priv_change."); + + $sOrphanCount = "SELECT COUNT(c.id) FROM `{$sDBPrefix}priv_change` AS c left join `{$sDBPrefix}priv_changeop` AS o ON c.id = o.changeid WHERE o.id IS NULL"; + $iOrphanCount = (int)CMDBSource::QueryToScalar($sOrphanCount); + SetupLog::Info("There are $iOrphanCount useless records in {$sDBPrefix}priv_change (".sprintf('%.2f', ((100.0 * $iOrphanCount) / $iTotalCount)).'%)'); + if ($iOrphanCount > 0) { + //N°3793 + if ($iOrphanCount > 100000) { + SetupLog::Info("There are too much useless records ($iOrphanCount) in {$sDBPrefix}priv_change. Cleanup cannot be done during setup."); + } else { + SetupLog::Info('Removing the orphan records...'); + $sCleanup = "DELETE FROM `{$sDBPrefix}priv_change` USING `{$sDBPrefix}priv_change` LEFT JOIN `{$sDBPrefix}priv_changeop` ON `{$sDBPrefix}priv_change`.id = `{$sDBPrefix}priv_changeop`.changeid WHERE `{$sDBPrefix}priv_changeop`.id IS NULL;"; + CMDBSource::Query($sCleanup); + SetupLog::Info('Cleanup completed successfully.'); + } + } else { + SetupLog::Info('Ok, nothing to cleanup.'); + } + } catch (Exception $e) { + SetupLog::Info("Cleanup of orphan records in `{$sDBPrefix}priv_change` failed: ".$e->getMessage()); + } + } + } + + public function MigrateDataAfterUpdateStructure(string $sMode, Config $oConfig): void + { + $this->InitDataModel($oConfig); + + $sDBName = $oConfig->Get('db_name'); + $sDBPrefix = $oConfig->Get('db_subname'); + + // priv_change now has an 'origin' field to distinguish between the various input sources + // Let's initialize the field with 'interactive' for all records where it's null + // Then check if some records should hold a different value, based on a pattern matching in the userinfo field + CMDBSource::SelectDB($sDBName); + try { + $sCount = "SELECT COUNT(*) FROM `{$sDBPrefix}priv_change` WHERE `origin` IS NULL"; + $iCount = (int)CMDBSource::QueryToScalar($sCount); + if ($iCount > 0) { + SetupLog::Info("Initializing '{$sDBPrefix}priv_change.origin' ($iCount records to update)"); + + // By default all uninitialized values are considered as 'interactive' + $sInit = "UPDATE `{$sDBPrefix}priv_change` SET `origin` = 'interactive' WHERE `origin` IS NULL"; + CMDBSource::Query($sInit); + + // CSV Import was identified by the comment at the end + $sInit = "UPDATE `{$sDBPrefix}priv_change` SET `origin` = 'csv-import.php' WHERE `userinfo` LIKE '%Web Service (CSV)'"; + CMDBSource::Query($sInit); + + // CSV Import was identified by the comment at the end + $sInit = "UPDATE `{$sDBPrefix}priv_change` SET `origin` = 'csv-interactive' WHERE `userinfo` LIKE '%(CSV)' AND origin = 'interactive'"; + CMDBSource::Query($sInit); + + // Syncho data sources were identified by the comment at the end + // Unfortunately the comment is localized, so we have to search for all possible patterns + $sCurrentLanguage = Dict::GetUserLanguage(); + $aSuffixes = []; + foreach (array_keys(Dict::GetLanguages()) as $sLangCode) { + Dict::SetUserLanguage($sLangCode); + $sSuffix = CMDBSource::Quote('%'.Dict::S('Core:SyncDataExchangeComment')); + $aSuffixes[$sSuffix] = true; + } + Dict::SetUserLanguage($sCurrentLanguage); + $sCondition = '`userinfo` LIKE '.implode(' OR `userinfo` LIKE ', array_keys($aSuffixes)); + + $sInit = "UPDATE `{$sDBPrefix}priv_change` SET `origin` = 'synchro-data-source' WHERE ($sCondition)"; + CMDBSource::Query($sInit); + + SetupLog::Info("Initialization of '{$sDBPrefix}priv_change.origin' completed."); + } else { + SetupLog::Info("'{$sDBPrefix}priv_change.origin' already initialized, nothing to do."); + } + } catch (Exception $e) { + SetupLog::Error("Initializing '{$sDBPrefix}priv_change.origin' failed: ".$e->getMessage()); + } + + // priv_async_task now has a 'status' field to distinguish between the various statuses rather than just relying on the date columns + // Let's initialize the field with 'planned' or 'error' for all records were it's null + CMDBSource::SelectDB($sDBName); + try { + $sCount = "SELECT COUNT(*) FROM `{$sDBPrefix}priv_async_task` WHERE `status` IS NULL"; + $iCount = (int)CMDBSource::QueryToScalar($sCount); + if ($iCount > 0) { + SetupLog::Info("Initializing '{$sDBPrefix}priv_async_task.status' ($iCount records to update)"); + + $sInit = "UPDATE `{$sDBPrefix}priv_async_task` SET `status` = 'planned' WHERE (`status` IS NULL) AND (`started` IS NULL)"; + CMDBSource::Query($sInit); + + $sInit = "UPDATE `{$sDBPrefix}priv_async_task` SET `status` = 'error' WHERE (`status` IS NULL) AND (`started` IS NOT NULL)"; + CMDBSource::Query($sInit); + + SetupLog::Info("Initialization of '{$sDBPrefix}priv_async_task.status' completed."); + } else { + SetupLog::Info("'{$sDBPrefix}priv_async_task.status' already initialized, nothing to do."); + } + } catch (Exception $e) { + SetupLog::Error("Initializing '{$sDBPrefix}priv_async_task.status' failed: ".$e->getMessage()); } } /** * Analyzes the current installation and the possibilities * - * @param null|Config $oConfig Defines the target environment (DB) + * @param null|Config $oConfig Defines the build environment (DB) * @param mixed $modulesPath Either a single string or an array of absolute paths * @param bool $bAbortOnMissingDependency ... * @param array $aModulesToLoad List of modules to search for, defaults to all if omitted @@ -145,12 +323,12 @@ class RunTimeEnvironment * @return array Array with the following format: * array => * 'iTop' => array( - * 'version_db' => ... (could be empty in case of a fresh install) - * 'version_code => ... + * 'installed_version' => ... (could be empty in case of a fresh install) + * 'available_version => ... * ) * => array( - * 'version_db' => ... - * 'version_code' => ... + * 'installed_version' => ... + * 'available_version' => ... * 'install' => array( * 'flag' => SETUP_NEVER | SETUP_OPTIONAL | SETUP_MANDATORY * 'message' => ... @@ -168,137 +346,41 @@ class RunTimeEnvironment */ public function AnalyzeInstallation($oConfig, $modulesPath, $bAbortOnMissingDependency = false, $aModulesToLoad = null) { - $aRes = [ - ROOT_MODULE => [ - 'version_db' => '', - 'name_db' => '', - 'version_code' => ITOP_VERSION_FULL, - 'name_code' => ITOP_APPLICATION, - ], - ]; + return AnalyzeInstallation::GetInstance()->AnalyzeInstallation($oConfig, $modulesPath, $bAbortOnMissingDependency, $aModulesToLoad); + } - $aDirs = is_array($modulesPath) ? $modulesPath : [$modulesPath]; - $aModules = ModuleDiscovery::GetAvailableModules($aDirs, $bAbortOnMissingDependency, $aModulesToLoad); - foreach ($aModules as $sModuleId => $aModuleInfo) { - list($sModuleName, $sModuleVersion) = ModuleDiscovery::GetModuleName($sModuleId); - if ($sModuleName == '') { - throw new Exception("Missing name for the module: '$sModuleId'"); - } - if ($sModuleVersion == '') { - // The version must not be empty (it will be used as a criteria to determine wether a module has been installed or not) - //throw new Exception("Missing version for the module: '$sModuleId'"); - $sModuleVersion = '1.0.0'; - } + /** + * @param \Config $oConfig + * @param string $sDataModelVersion + * @param array $aSelectedModuleCodes + * @param array $aSelectedExtensionCodes + * @param string|null $sInstallComment + * + * @throws \CoreException + * @throws \DictExceptionUnknownLanguage + * @throws \MySQLException + * @throws \Exception + */ + public function DoCreateConfig(Config $oConfig, string $sDataModelVersion, array $aSelectedModuleCodes, array $aSelectedExtensionCodes, ?string $sInstallComment = null, string $sSourceDesc = 'Setup') + { + $oConfig->Set('access_mode', ACCESS_FULL); - $sModuleAppVersion = $aModuleInfo['itop_version']; - $aModuleInfo['version_db'] = ''; - $aModuleInfo['version_code'] = $sModuleVersion; + // Record which modules are installed... + $this->InitDataModel($oConfig, true); // load data model and connect to the database - if (!in_array($sModuleAppVersion, ['1.0.0', '1.0.1', '1.0.2'])) { - // This module is NOT compatible with the current version - $aModuleInfo['install'] = [ - 'flag' => MODULE_ACTION_IMPOSSIBLE, - 'message' => 'the module is not compatible with the current version of the application', - ]; - } elseif ($aModuleInfo['mandatory']) { - $aModuleInfo['install'] = [ - 'flag' => MODULE_ACTION_MANDATORY, - 'message' => 'the module is part of the application', - ]; - } else { - $aModuleInfo['install'] = [ - 'flag' => MODULE_ACTION_OPTIONAL, - 'message' => '', - ]; - } - $aRes[$sModuleName] = $aModuleInfo; + if (!$this->RecordInstallation($oConfig, $sDataModelVersion, $aSelectedModuleCodes, $aSelectedExtensionCodes, $sInstallComment)) { + throw new Exception('Failed to record the installation information'); } - try { - $aSelectInstall = []; - if (! is_null($oConfig)) { - CMDBSource::InitFromConfig($oConfig); - $aSelectInstall = CMDBSource::QueryToArray("SELECT * FROM ".$oConfig->Get('db_subname')."priv_module_install"); - } - } catch (MySQLException $e) { - // No database or erroneous information - } + $oConfig->UpdateIncludes('env-'.$this->sBuildEnv); + $sEnvironmentLabel = $this->GetFinalEnv().' (built on '.date('Y-m-d').')'; + $oConfig->Set('app_env_label', $sEnvironmentLabel, $sSourceDesc); - // Build the list of installed module (get the latest installation) - // - $aInstallByModule = []; // array of => array ('installed' => timestamp, 'version' => ) - $iRootId = 0; - foreach ($aSelectInstall as $aInstall) { - if (($aInstall['parent_id'] == 0) && ($aInstall['name'] != 'datamodel')) { - // Root module, what is its ID ? - $iId = (int) $aInstall['id']; - if ($iId > $iRootId) { - $iRootId = $iId; - } - } - } + $this->WriteConfigFileSafe($oConfig); - foreach ($aSelectInstall as $aInstall) { - //$aInstall['comment']; // unsused - $iInstalled = strtotime($aInstall['installed']); - $sModuleName = $aInstall['name']; - $sModuleVersion = $aInstall['version']; - if ($sModuleVersion == '') { - // Though the version cannot be empty in iTop 2.0, it used to be possible - // therefore we have to put something here or the module will not be considered - // as being installed - $sModuleVersion = '0.0.0'; - } - - if ($aInstall['parent_id'] == 0) { - $sModuleName = ROOT_MODULE; - } elseif ($aInstall['parent_id'] != $iRootId) { - // Skip all modules belonging to previous installations - continue; - } - - if (array_key_exists($sModuleName, $aInstallByModule)) { - if ($iInstalled < $aInstallByModule[$sModuleName]['installed']) { - continue; - } - } - - if ($aInstall['parent_id'] == 0) { - $aRes[$sModuleName]['version_db'] = $sModuleVersion; - $aRes[$sModuleName]['name_db'] = $aInstall['name']; - } - - $aInstallByModule[$sModuleName]['installed'] = $iInstalled; - $aInstallByModule[$sModuleName]['version'] = $sModuleVersion; - } - - // Adjust the list of proposed modules - // - foreach ($aInstallByModule as $sModuleName => $aModuleDB) { - if ($sModuleName == ROOT_MODULE) { - continue; - } // Skip the main module - - if (!array_key_exists($sModuleName, $aRes)) { - // A module was installed, it is not proposed in the new build... skip - continue; - } - $aRes[$sModuleName]['version_db'] = $aModuleDB['version']; - - if ($aRes[$sModuleName]['install']['flag'] == MODULE_ACTION_MANDATORY) { - $aRes[$sModuleName]['uninstall'] = [ - 'flag' => MODULE_ACTION_IMPOSSIBLE, - 'message' => 'the module is part of the application', - ]; - } else { - $aRes[$sModuleName]['uninstall'] = [ - 'flag' => MODULE_ACTION_OPTIONAL, - 'message' => '', - ]; - } - } - - return $aRes; + // Ready to go !! + require_once(APPROOT.'core/dict.class.inc.php'); + MetaModel::ResetAllCaches(); } /** @@ -309,14 +391,14 @@ class RunTimeEnvironment public function WriteConfigFileSafe($oConfig) { self::MakeDirSafe(APPCONF); - self::MakeDirSafe(APPCONF.$this->sTargetEnv); + self::MakeDirSafe(APPCONF.$this->sBuildEnv); - $sTargetConfigFile = APPCONF.$this->sTargetEnv.'/'.ITOP_CONFIG_FILE; + $sBuildConfigFile = APPCONF.$this->sBuildEnv.'/'.ITOP_CONFIG_FILE; // Write the config file - @chmod($sTargetConfigFile, 0770); // In case it exists: RWX for owner and group, nothing for others - $oConfig->WriteToFile($sTargetConfigFile); - @chmod($sTargetConfigFile, 0440); // Read-only for owner and group, nothing for others + @chmod($sBuildConfigFile, 0770); // In case it exists: RWX for owner and group, nothing for others + $oConfig->WriteToFile($sBuildConfigFile); + @chmod($sBuildConfigFile, 0440); // Read-only for owner and group, nothing for others } /** @@ -339,6 +421,25 @@ class RunTimeEnvironment return ($oExtension->sSource == iTopExtension::SOURCE_REMOTE); } + public function GetExtraDirsToCompile(string $sSourceDir): array + { + $sSourceDirFull = APPROOT.$sSourceDir; + if (!is_dir($sSourceDirFull)) { + throw new Exception("The source directory '$sSourceDirFull' does not exist (or could not be read)"); + } + $aDirsToCompile = [$sSourceDirFull]; + + if (is_dir(APPROOT.'extensions')) { + $aDirsToCompile[] = APPROOT.'extensions'; + } + $sExtraDir = utils::GetDataPath().$this->sBuildEnv.'-modules/'; + if (is_dir($sExtraDir)) { + $aDirsToCompile[] = $sExtraDir; + } + + return $aDirsToCompile; + } + /** * Get the installed modules (only the installed ones) */ @@ -352,7 +453,7 @@ class RunTimeEnvironment if (is_dir(APPROOT.'extensions')) { $aDirsToCompile[] = APPROOT.'extensions'; } - $sExtraDir = utils::GetDataPath().$this->sTargetEnv.'-modules/'; + $sExtraDir = utils::GetDataPath().$this->sBuildEnv.'-modules/'; if (is_dir($sExtraDir)) { $aDirsToCompile[] = $sExtraDir; } @@ -360,30 +461,29 @@ class RunTimeEnvironment $aExtraDirs = $this->GetExtraDirsToScan($aDirsToCompile); $aDirsToCompile = array_merge($aDirsToCompile, $aExtraDirs); - $aRet = []; - - // Determine the installed modules and extensions - // $oSourceConfig = new Config(APPCONF.$sSourceEnv.'/'.ITOP_CONFIG_FILE); - $oSourceEnv = new RunTimeEnvironment($sSourceEnv); - $aAvailableModules = $oSourceEnv->AnalyzeInstallation($oSourceConfig, $aDirsToCompile); - // Actually read the modules available for the target environment, + // Actually read the modules available for the build environment, // but get the selection from the source environment and finally - // mark as (automatically) chosen alll the "remote" modules present in the - // target environment (data/-modules) + // mark as (automatically) chosen all the "remote" modules present in the + // build environment (data/-modules) // The actual choices will be recorded by RecordInstallation below - $this->oExtensionsMap = new iTopExtensionsMap($this->sTargetEnv, $aExtraDirs); - $this->oExtensionsMap->LoadChoicesFromDatabase($oSourceConfig); - foreach ($this->oExtensionsMap->GetAllExtensions() as $oExtension) { + $this->InitExtensionMap($aExtraDirs, $oSourceConfig); + $this->GetExtensionMap()->LoadChoicesFromDatabase($oSourceConfig); + foreach ($this->GetExtensionMap()->GetAllExtensions() as $oExtension) { if ($this->IsExtensionSelected($oExtension)) { - $this->oExtensionsMap->MarkAsChosen($oExtension->sCode); + $this->GetExtensionMap()->MarkAsChosen($oExtension->sCode); } } + $aModulesToLoad = $this->GetModulesToLoad($this->sFinalEnv, $aDirsToCompile); + $aAvailableModules = $this->AnalyzeInstallation($oSourceConfig, $aDirsToCompile, true, $aModulesToLoad); + // Do load the required modules // $oDictModule = new MFDictModule('dictionaries', 'iTop Dictionaries', APPROOT.'dictionaries'); + + $aRet = []; $aRet[$oDictModule->GetName()] = $oDictModule; $oFactory = new ModelFactory($aDirsToCompile); @@ -401,16 +501,15 @@ class RunTimeEnvironment $aModules = $oFactory->FindModules(); foreach ($aModules as $oModule) { $sModule = $oModule->GetName(); - $sModuleRootDir = $oModule->GetRootDir(); - $bIsExtra = $this->oExtensionsMap->ModuleIsChosenAsPartOfAnExtension($sModule, iTopExtension::SOURCE_REMOTE); + $bIsExtra = $this->GetExtensionMap()->ModuleIsChosenAsPartOfAnExtension($sModule, iTopExtension::SOURCE_REMOTE); if (array_key_exists($sModule, $aAvailableModules)) { - if (($aAvailableModules[$sModule]['version_db'] != '') || $bIsExtra && !$oModule->IsAutoSelect()) { //Extra modules are always unless they are 'AutoSelect' + if (($aAvailableModules[$sModule]['installed_version'] != '') || $bIsExtra && !$oModule->IsAutoSelect()) { //Extra modules are always unless they are 'AutoSelect' $aRet[$oModule->GetName()] = $oModule; } } } - $oPhpExpressionEvaluator = new PhpExpressionEvaluator([], RunTimeEnvironment::STATIC_CALL_AUTOSELECT_WHITELIST); + $oPhpExpressionEvaluator = new PhpExpressionEvaluator([], ModuleFileReader::STATIC_CALL_AUTOSELECT_WHITELIST); // Now process the 'AutoSelect' modules do { @@ -423,7 +522,7 @@ class RunTimeEnvironment $bSelected = $oPhpExpressionEvaluator->ParseAndEvaluateBooleanExpression($oModule->GetAutoSelect()); if ($bSelected) { $aRet[$oModule->GetName()] = $oModule; // store the Id of the selected module - $bModuleAdded = true; + $bModuleAdded = true; } } catch (ModuleFileReaderException $e) { //do nothing. logged already @@ -432,7 +531,7 @@ class RunTimeEnvironment } } while ($bModuleAdded); - $sDeltaFile = utils::GetDataPath().$this->sTargetEnv.'.delta.xml'; + $sDeltaFile = utils::GetDataPath().$this->sBuildEnv.'.delta.xml'; if (file_exists($sDeltaFile)) { $oDelta = new MFDeltaModule($sDeltaFile); $aRet[$oDelta->GetName()] = $oDelta; @@ -441,55 +540,6 @@ class RunTimeEnvironment return $aRet; } - /** - * Compile the data model by imitating the given environment - * The list of modules to be installed in the target environment is: - * - the list of modules present in the "source_dir" (defined by the source environment) which are marked as "installed" in the source environment's database - * - plus the list of modules present in the "extra" directory of the target environment: data/-modules/ - * - * @param string $sSourceEnv The name of the source environment to 'imitate' - * @param bool $bUseSymLinks Whether to create symbolic links instead of copies - * - * @return string[] - */ - public function CompileFrom($sSourceEnv, $bUseSymLinks = null) - { - $oSourceConfig = new Config(utils::GetConfigFilePath($sSourceEnv)); - $sSourceDir = $oSourceConfig->Get('source_dir'); - - $sSourceDirFull = APPROOT.$sSourceDir; - // Do load the required modules - // - $oFactory = new ModelFactory($sSourceDirFull); - $aModulesToCompile = $this->GetMFModulesToCompile($sSourceEnv, $sSourceDir); - foreach ($aModulesToCompile as $oModule) { - if ($oModule instanceof MFDeltaModule) { - // Just before loading the delta, let's save an image of the datamodel - // in case there is no delta the operation will be done after the end of the loop - $oFactory->SaveToFile(utils::GetDataPath().'datamodel-'.$this->sTargetEnv.'.xml'); - } - $oFactory->LoadModule($oModule); - } - - if ($oModule instanceof MFDeltaModule) { - // A delta was loaded, let's save a second copy of the datamodel - $oFactory->SaveToFile(utils::GetDataPath().'datamodel-'.$this->sTargetEnv.'-with-delta.xml'); - } else { - // No delta was loaded, let's save the datamodel now - $oFactory->SaveToFile(utils::GetDataPath().'datamodel-'.$this->sTargetEnv.'.xml'); - } - - $sTargetDir = APPROOT.'env-'.$this->sTargetEnv; - self::MakeDirSafe($sTargetDir); - $bSkipTempDir = ($this->sFinalEnv != $this->sTargetEnv); // No need for a temporary directory if sTargetEnv is already a temporary directory - $oMFCompiler = new MFCompiler($oFactory, $this->sFinalEnv); - $oMFCompiler->Compile($sTargetDir, null, $bUseSymLinks, $bSkipTempDir); - - MetaModel::ResetAllCaches($this->sTargetEnv); - - return array_keys($aModulesToCompile); - } - /** * Helper function to create the database structure * @@ -569,6 +619,81 @@ class RunTimeEnvironment return true; } + /** + * @param \Config $oConfig + * @param string $sMode + * @param array|null $aSelectedModules null means all + * + * @return void + * @throws \CoreException + * @throws \DictExceptionUnknownLanguage + * @throws \MySQLException + * @throws \MySQLHasGoneAwayException + * @throws \OQLException + */ + public function UpdateDBSchema(Config $oConfig, string $sMode, ?array $aSelectedModules = null): void + { + $this->InitDataModel($oConfig); // load data model only + + // Module specific actions (migrate the data) + $aAvailableModules = $this->AnalyzeInstallation($oConfig, $this->GetBuildDir()); + $this->CallInstallerHandlers($aAvailableModules, 'BeforeDatabaseCreation', $aSelectedModules); + + if (!$this->CreateDatabaseStructure(MetaModel::GetConfig(), $sMode)) { + throw new Exception("Failed to create/upgrade the database structure for environment"); + } + } + + public function SetDbUUID(): void + { + // Set a DBProperty with a unique ID to identify this instance of iTop + $sUUID = DBProperty::GetProperty('database_uuid', ''); + if ($sUUID === '') { + $sUUID = utils::CreateUUID('database'); + DBProperty::SetProperty('database_uuid', $sUUID, 'Installation/upgrade of '.ITOP_APPLICATION, 'Unique ID of this '.ITOP_APPLICATION.' Database'); + } + } + + /** + * @param \Config $oConfig + * @param array|null $aSelectedModules null means all + * + * @return void + * @throws \CoreException + * @throws \DictExceptionUnknownLanguage + * @throws \MySQLException + * @throws \Exception + */ + public function AfterDBCreate(Config $oConfig, string $sMode, ?array $aSelectedModules = null, array $aAdminParams = []): void + { + $this->InitDataModel($oConfig); // load data model and connect to the database + + // Perform here additional DB setup... profiles, etc... + // + $aAvailableModules = $this->AnalyzeInstallation($oConfig, $this->GetBuildDir()); + $this->CallInstallerHandlers($aAvailableModules, 'AfterDatabaseCreation', $aSelectedModules); + + $this->UpdatePredefinedObjects(); + + if ($sMode == 'install') { + SetupLog::Info('CreateAdminAccount'); + + $sAdminUser = $aAdminParams['user']; + $sAdminPwd = $aAdminParams['pwd']; + $sAdminLanguage = $aAdminParams['language']; + + if (!UserRights::CreateAdministrator($sAdminUser, $sAdminPwd, $sAdminLanguage)) { + throw(new Exception("Failed to create the administrator account '$sAdminUser'")); + } else { + SetupLog::Info("Administrator account '$sAdminUser' created."); + } + } + + // Perform final setup tasks here + // + $this->CallInstallerHandlers($aAvailableModules, 'AfterDatabaseSetup', $aSelectedModules); + } + public function UpdatePredefinedObjects() { // Have it work fine even if the DB has been set in read-only mode for the users @@ -604,7 +729,7 @@ class RunTimeEnvironment } } foreach ($aPredefinedObjects as $iRefId => $aObjValues) { - if (! array_key_exists($iRefId, $aDBIds)) { + if (!array_key_exists($iRefId, $aDBIds)) { $oNewObj = MetaModel::NewObject($sClass); $oNewObj->SetKey($iRefId); foreach ($aObjValues as $sAttCode => $value) { @@ -648,7 +773,7 @@ class RunTimeEnvironment $oInstallRec->Set('comment', json_encode($aData)); $oInstallRec->Set('parent_id', 0); // root module $oInstallRec->Set('installed', $iInstallationTime); - $iMainItopRecord = $oInstallRec->DBInsertNoReload(); + $oInstallRec->DBInsertNoReload(); // Record main installation $oInstallRec = new ModuleInstallation(); @@ -661,15 +786,19 @@ class RunTimeEnvironment // Record installed modules and extensions // - $aAvailableExtensions = []; $aAvailableModules = $this->AnalyzeInstallation($oConfig, $this->GetBuildDir()); foreach ($aSelectedModuleCodes as $sModuleId) { + if (($sModuleId == ROOT_MODULE) || ($sModuleId == DATAMODEL_MODULE)) { + continue; + } + if (!array_key_exists($sModuleId, $aAvailableModules)) { continue; } + $aModuleData = $aAvailableModules[$sModuleId]; $sName = $sModuleId; - $sVersion = $aModuleData['version_code']; + $sVersion = $aModuleData['available_version']; $sUninstallable = $aModuleData['uninstallable'] ?? 'yes'; $aComments = []; $aComments[] = $sShortComment; @@ -702,16 +831,17 @@ class RunTimeEnvironment $oInstallRec->DBInsertNoReload(); } - if ($this->oExtensionsMap) { + if ($this->GetExtensionMap()) { // Mark as chosen the selected extensions code passed to us + // Note: some other extensions may already be marked as chosen - foreach ($this->oExtensionsMap->GetAllExtensions() as $oExtension) { + foreach ($this->GetExtensionMap()->GetAllExtensions() as $oExtension) { if (in_array($oExtension->sCode, $aSelectedExtensionCodes)) { - $this->oExtensionsMap->MarkAsChosen($oExtension->sCode); + $this->GetExtensionMap()->MarkAsChosen($oExtension->sCode); } } - foreach ($this->oExtensionsMap->GetChoices() as $oExtension) { + foreach ($this->GetExtensionMap()->GetChoices() as $oExtension) { $oInstallRec = new ExtensionInstallation(); $oInstallRec->Set('code', $oExtension->sCode); $oInstallRec->Set('label', $oExtension->sLabel); @@ -739,9 +869,7 @@ class RunTimeEnvironment public function GetApplicationVersion(Config $oConfig) { try { - CMDBSource::InitFromConfig($oConfig); - $sSQLQuery = "SELECT * FROM ".$oConfig->Get('db_subname')."priv_module_install"; - $aSelectInstall = CMDBSource::QueryToArray($sSQLQuery); + $aSelectInstall = ModuleInstallationRepository::GetInstance()->ReadFromDB($oConfig); } catch (MySQLException $e) { // No database or erroneous information $this->log_error('Can not connect to the database: host: '.$oConfig->Get('db_host').', user:'.$oConfig->Get('db_user').', pwd:'.$oConfig->Get('db_pwd').', db name:'.$oConfig->Get('db_name')); @@ -779,7 +907,8 @@ class RunTimeEnvironment $aResult['datamodel_version'] = $aResult['product_version']; } $this->log_info("GetApplicationVersion returns: product_name: ".$aResult['product_name'].', product_version: '.$aResult['product_version']); - return empty($aResult) ? false : $aResult; + + return count($aResult) == 0 ? false : $aResult; } public static function MakeDirSafe($sDir) @@ -799,14 +928,17 @@ class RunTimeEnvironment { SetupLog::Error($sText); } + protected function log_warning($sText) { SetupLog::Warning($sText); } + protected function log_info($sText) { SetupLog::Info($sText); } + protected function log_ok($sText) { SetupLog::Ok($sText); @@ -838,13 +970,19 @@ class RunTimeEnvironment if ($oLatestDM == null) { return '0.0.0'; } + return $oLatestDM->Get('version'); } - public function Commit() + /** + * Move the build env to the final env if all the steps went ok + * + * @return void + */ + public function Commit(): void { - if ($this->sFinalEnv != $this->sTargetEnv) { - if (file_exists(utils::GetDataPath().$this->sTargetEnv.'.delta.xml')) { + if ($this->sFinalEnv != $this->sBuildEnv) { + if (file_exists(utils::GetDataPath().$this->sBuildEnv.'.delta.xml')) { if (file_exists(utils::GetDataPath().$this->sFinalEnv.'.delta.xml')) { // Make a "previous" file copy( @@ -853,58 +991,65 @@ class RunTimeEnvironment ); } $this->CommitFile( - utils::GetDataPath().$this->sTargetEnv.'.delta.xml', + utils::GetDataPath().$this->sBuildEnv.'.delta.xml', utils::GetDataPath().$this->sFinalEnv.'.delta.xml' ); } $this->CommitFile( - utils::GetDataPath().'datamodel-'.$this->sTargetEnv.'.xml', + utils::GetDataPath().'datamodel-'.$this->sBuildEnv.'.xml', utils::GetDataPath().'datamodel-'.$this->sFinalEnv.'.xml' ); $this->CommitFile( - utils::GetDataPath().'datamodel-'.$this->sTargetEnv.'-with-delta.xml', + utils::GetDataPath().'datamodel-'.$this->sBuildEnv.'-with-delta.xml', utils::GetDataPath().'datamodel-'.$this->sFinalEnv.'-with-delta.xml', false ); $this->CommitDir( - utils::GetDataPath().$this->sTargetEnv.'-modules/', + utils::GetDataPath().$this->sBuildEnv.'-modules/', utils::GetDataPath().$this->sFinalEnv.'-modules/', false ); $this->CommitDir( - utils::GetDataPath().'cache-'.$this->sTargetEnv, + utils::GetDataPath().'cache-'.$this->sBuildEnv, utils::GetDataPath().'cache-'.$this->sFinalEnv, false ); $this->CommitDir( - APPROOT.'env-'.$this->sTargetEnv, + APPROOT.'env-'.$this->sBuildEnv, APPROOT.'env-'.$this->sFinalEnv, true, false ); + $this->RerouteSymlinks(APPROOT.'env-'.$this->sFinalEnv, utils::GetDataPath().$this->sBuildEnv.'-modules/', utils::GetDataPath().$this->sFinalEnv.'-modules/'); + // Move the config file // - $sTargetConfig = APPCONF.$this->sTargetEnv.'/config-itop.php'; + $sBuildConfig = APPCONF.$this->sBuildEnv.'/config-itop.php'; $sFinalConfig = APPCONF.$this->sFinalEnv.'/config-itop.php'; @chmod($sFinalConfig, 0770); // In case it exists: RWX for owner and group, nothing for others - $this->CommitFile($sTargetConfig, $sFinalConfig); + $this->CommitFile($sBuildConfig, $sFinalConfig); @chmod($sFinalConfig, 0440); // Read-only for owner and group, nothing for others - @rmdir(dirname($sTargetConfig)); // Cleanup the temporary build dir if empty + @rmdir(dirname($sBuildConfig)); // Cleanup the temporary build dir if empty - MetaModel::ResetAllCaches($this->sFinalEnv); + if (! isset($_SESSION)) { + //used in all UI setups (not unattended) + session_start(); + } + $_SESSION['itop_env'] = $this->sFinalEnv; } } /** * Overwrite or create the destination file * - * @param $sSource - * @param $sDest + * @param string $sSource + * @param string $sDest * @param bool $bSourceMustExist - * @throws Exception + * + * @throws \Exception */ - protected function CommitFile($sSource, $sDest, $bSourceMustExist = true) + protected function CommitFile(string $sSource, string $sDest, bool $bSourceMustExist = true): void { if (file_exists($sSource)) { SetupUtils::builddir(dirname($sDest)); @@ -938,6 +1083,7 @@ class RunTimeEnvironment * @param $sDest * @param boolean $bSourceMustExist * @param boolean $bRemoveSource If true $sSource will be removed, otherwise $sSource will just be emptied + * * @throws Exception */ protected function CommitDir($sSource, $sDest, $bSourceMustExist = true, $bRemoveSource = true) @@ -959,24 +1105,32 @@ class RunTimeEnvironment public function Rollback() { - if ($this->sFinalEnv != $this->sTargetEnv) { - SetupUtils::tidydir(APPROOT.'env-'.$this->sTargetEnv); + if ($this->sFinalEnv != $this->sBuildEnv) { + SetupUtils::tidydir(APPROOT.'env-'.$this->sBuildEnv); } } /** * Call the given handler method for all selected modules having an installation handler + * * @param array[] $aAvailableModules - * @param string[] $aSelectedModules * @param string $sHandlerName + * @param string[]|null $aSelectedModules + * * @throws CoreException */ - public function CallInstallerHandlers($aAvailableModules, $aSelectedModules, $sHandlerName) + public function CallInstallerHandlers($aAvailableModules, $sHandlerName, $aSelectedModules = null) { foreach ($aAvailableModules as $sModuleId => $aModule) { - if (($sModuleId != ROOT_MODULE) && in_array($sModuleId, $aSelectedModules)) { - $aArgs = [MetaModel::GetConfig(), $aModule['version_db'], $aModule['version_code']]; - RunTimeEnvironment::CallInstallerHandler($aAvailableModules[$sModuleId], $sHandlerName, $aArgs); + if (($sModuleId == ROOT_MODULE) || ($sModuleId == DATAMODEL_MODULE)) { + continue; + } + + if (is_null($aSelectedModules) || in_array($sModuleId, $aSelectedModules)) { + $oConfig = MetaModel::GetConfig(); + $oConfig->Set('access_mode', ACCESS_FULL); + $aArgs = [$oConfig, $aModule['installed_version'], $aModule['available_version']]; + RunTimeEnvironment::CallInstallerHandler($aModule, $sHandlerName, $aArgs); } } } @@ -1003,27 +1157,49 @@ class RunTimeEnvironment try { call_user_func_array($aCallSpec, $aArgs); } catch (Exception $e) { + $sModuleId = $aModuleInfo[ModuleFileReader::MODULE_INFO_ID] ?? ""; $sErrorMessage = "Module $sModuleId : error when calling module installer class $sModuleInstallerClass for $sHandlerName handler"; $aExceptionContextData = [ - 'ModulelId' => $sModuleId, - 'ModuleInstallerClass' => $sModuleInstallerClass, + 'ModulelId' => $sModuleId, + 'ModuleInstallerClass' => $sModuleInstallerClass, 'ModuleInstallerHandler' => $sHandlerName, - 'ExceptionClass' => get_class($e), - 'ExceptionMessage' => $e->getMessage(), + 'ExceptionClass' => get_class($e), + 'ExceptionMessage' => $e->getMessage(), ]; + IssueLog::Exception($sErrorMessage, $e, null, $aExceptionContextData); throw new CoreException($sErrorMessage, $aExceptionContextData, '', $e); } } } + public function DoLoadData(Config $oConfig, bool $bSampleData = false, $aSelectedModules = null) + { + $this->InitDataModel($oConfig, false); // load data model and connect to the database + + // Perform here additional DB setup... profiles, etc... + // + $aAvailableModules = $this->AnalyzeInstallation($oConfig, $this->GetBuildDir()); + + $this->LoadData($aAvailableModules, $bSampleData, $aSelectedModules); + + $this->CallInstallerHandlers($aAvailableModules, 'AfterDataLoad', $aSelectedModules); + + } + /** * Load data from XML files for the selected modules (structural data and/or sample data) - * @param array[] $aAvailableModules All available modules and their definition - * @param string[] $aSelectedModules List of selected modules - * @param bool $bSampleData Wether or not to load sample data + * + * @param array $aAvailableModules + * @param bool $bSampleData Whether or not to load sample data + * @param null $aSelectedModules List of selected modules + * + * @throws \CoreException */ - public function LoadData($aAvailableModules, $aSelectedModules, $bSampleData) + public function LoadData($aAvailableModules, $bSampleData, $aSelectedModules = null) { + $oConfig = MetaModel::GetConfig(); + $oConfig->Set('access_mode', ACCESS_FULL); + $oDataLoader = new XMLDataLoader(); CMDBObject::SetCurrentChangeFromParams("Initialization from XML files for the selected modules "); @@ -1035,30 +1211,33 @@ class RunTimeEnvironment $aFiles = []; $aPreviouslyLoadedFiles = []; foreach ($aAvailableModules as $sModuleId => $aModule) { - if (($sModuleId != ROOT_MODULE)) { - $sRelativePath = 'env-'.$this->sTargetEnv.'/'.basename($aModule['root_dir']); - // Load data only for selected AND newly installed modules - if (in_array($sModuleId, $aSelectedModules)) { - if ($aModule['version_db'] != '') { - // Simulate the load of the previously loaded XML files to get the mapping of the keys - if ($bSampleData) { - $aPreviouslyLoadedFiles = static::MergeWithRelativeDir($aPreviouslyLoadedFiles, $sRelativePath, $aAvailableModules[$sModuleId]['data.struct']); - $aPreviouslyLoadedFiles = static::MergeWithRelativeDir($aPreviouslyLoadedFiles, $sRelativePath, $aAvailableModules[$sModuleId]['data.sample']); - } else { - // Load only structural data - $aPreviouslyLoadedFiles = static::MergeWithRelativeDir($aPreviouslyLoadedFiles, $sRelativePath, $aAvailableModules[$sModuleId]['data.struct']); - } + if (($sModuleId == ROOT_MODULE) || ($sModuleId == DATAMODEL_MODULE)) { + continue; + } + + $sRelativePath = 'env-'.$this->sBuildEnv.'/'.basename($aModule['root_dir']); + // Load data only for selected AND newly installed modules + if (is_null($aSelectedModules) || in_array($sModuleId, $aSelectedModules)) { + if ($aModule['installed_version'] != '') { + // Simulate the load of the previously loaded XML files to get the mapping of the keys + if ($bSampleData) { + $aPreviouslyLoadedFiles = static::MergeWithRelativeDir($aPreviouslyLoadedFiles, $sRelativePath, $aAvailableModules[$sModuleId]['data.struct']); + $aPreviouslyLoadedFiles = static::MergeWithRelativeDir($aPreviouslyLoadedFiles, $sRelativePath, $aAvailableModules[$sModuleId]['data.sample']); } else { - if ($bSampleData) { - $aFiles = static::MergeWithRelativeDir($aFiles, $sRelativePath, $aAvailableModules[$sModuleId]['data.struct']); - $aFiles = static::MergeWithRelativeDir($aFiles, $sRelativePath, $aAvailableModules[$sModuleId]['data.sample']); - } else { - // Load only structural data - $aFiles = static::MergeWithRelativeDir($aFiles, $sRelativePath, $aAvailableModules[$sModuleId]['data.struct']); - } + // Load only structural data + $aPreviouslyLoadedFiles = static::MergeWithRelativeDir($aPreviouslyLoadedFiles, $sRelativePath, $aAvailableModules[$sModuleId]['data.struct']); + } + } else { + if ($bSampleData) { + $aFiles = static::MergeWithRelativeDir($aFiles, $sRelativePath, $aAvailableModules[$sModuleId]['data.struct']); + $aFiles = static::MergeWithRelativeDir($aFiles, $sRelativePath, $aAvailableModules[$sModuleId]['data.sample']); + } else { + // Load only structural data + $aFiles = static::MergeWithRelativeDir($aFiles, $sRelativePath, $aAvailableModules[$sModuleId]['data.struct']); } } } + } // Simulate the load of the previously loaded files, in order to initialize @@ -1067,7 +1246,7 @@ class RunTimeEnvironment foreach ($aPreviouslyLoadedFiles as $sFileRelativePath) { $sFileName = APPROOT.$sFileRelativePath; SetupLog::Info("Loading file: $sFileName (just to get the keys mapping)"); - if (empty($sFileName) || !file_exists($sFileName)) { + if (!file_exists($sFileName)) { throw(new Exception("File $sFileName does not exist")); } @@ -1079,7 +1258,7 @@ class RunTimeEnvironment foreach ($aFiles as $sFileRelativePath) { $sFileName = APPROOT.$sFileRelativePath; SetupLog::Info("Loading file: $sFileName"); - if (empty($sFileName) || !file_exists($sFileName)) { + if (!file_exists($sFileName)) { throw(new Exception("File $sFileName does not exist")); } @@ -1094,9 +1273,11 @@ class RunTimeEnvironment /** * Merge two arrays of file names, adding the relative path to the files provided in the array to merge + * * @param string[] $aSourceArray * @param string $sBaseDir * @param string[] $aFilesToMerge + * * @return string[] */ protected static function MergeWithRelativeDir($aSourceArray, $sBaseDir, $aFilesToMerge) @@ -1105,14 +1286,16 @@ class RunTimeEnvironment foreach ($aFilesToMerge as $sFile) { $aToMerge[] = $sBaseDir.'/'.$sFile; } + return array_merge($aSourceArray, $aToMerge); } /** * Check the MetaModel for some common pitfall (class name too long, classes requiring too many joins...) * The check takes about 900 ms for 200 classes - * @throws Exception + * * @return string + * @throws Exception */ public function CheckMetaModel() { @@ -1126,7 +1309,7 @@ class RunTimeEnvironment $oSearch = new DBObjectSearch($sClass); $oSearch->SetShowObsoleteData(false); - $oSQLQuery = $oSearch->GetSQLQueryStructure(null, false); + $oSQLQuery = $oSearch->GetSQLQueryStructure([], false); $sViewName = MetaModel::DBGetView($sClass); if (strlen($sViewName) > 64) { throw new Exception("Class name too long for class: '$sClass'. The name of the corresponding view ($sViewName) would exceed MySQL's limit for the name of a table (64 characters)."); @@ -1145,4 +1328,398 @@ class RunTimeEnvironment return sprintf("Checked %d classes in %.1f ms. No error found.\n", $iCount, $fDuration * 1000.0); } -} // End of class + + public function DataToCleanupAudit() + { + $oSetupAudit = new SetupAudit(ITOP_DEFAULT_ENV, $this->sBuildEnv); + + //Make sure the MetaModel is started before analysing for issues + $sConfFile = utils::GetConfigFilePath(ITOP_DEFAULT_ENV); + MetaModel::Startup($sConfFile, false, false); // Start on production environment + $oSetupAudit->RunDataAudit(true); + $iCount = $oSetupAudit->GetDataToCleanupCount(); + + if ($iCount > 0) { + throw new Exception("$iCount elements require data adjustments or cleanup in the backoffice", DataAuditSequencer::DATA_AUDIT_FAILED); + } + } + + public function CopySetupFiles(): void + { + $sSourceEnv = $this->sFinalEnv; + $sDestinationEnv = $this->sBuildEnv; + + if ($sDestinationEnv != $sSourceEnv) { + SetupUtils::CopyFile(utils::GetDataPath().$sSourceEnv.'.delta.xml', utils::GetDataPath().$sDestinationEnv.'.delta.xml'); + SetupUtils::copydir(utils::GetDataPath().$sSourceEnv.'-modules/', utils::GetDataPath().$sDestinationEnv.'-modules/'); + + // Copy the config file + // + $sFinalConfig = APPCONF.$sDestinationEnv.'/config-itop.php'; + if (is_file($sFinalConfig)) { + chmod($sFinalConfig, 0770); // In case it exists: RWX for owner and group, nothing for others + } + SetupUtils::copydir(APPCONF.$sSourceEnv, APPCONF.$sDestinationEnv); + MetaModel::ResetAllCaches($sDestinationEnv); + } + } + + /** + * Compile the data model by imitating the given environment + * The list of modules to be installed in the build environment is: + * - the list of modules present in the "source_dir" (defined by the source environment) which are marked as "installed" in the source environment's database + * - plus the list of modules present in the "extra" directory of the build environment: data/-modules/ + * + * @param string $sSourceEnv The name of the source environment to 'imitate' + * @param null $bUseSymLinks Whether to create symbolic links instead of copies + * + * @return string[] + * @throws \ConfigException + * @throws \CoreException + */ + public function CompileFrom($sSourceEnv, $bUseSymLinks = null) + { + $oSourceConfig = new Config(utils::GetConfigFilePath($sSourceEnv)); + $sSourceDir = $oSourceConfig->Get('source_dir'); + + $sSourceDirFull = APPROOT.$sSourceDir; + // Do load the required modules + // + $oFactory = new ModelFactory($sSourceDirFull); + $aModulesToCompile = $this->GetMFModulesToCompile($sSourceEnv, $sSourceDir); + $oModule = null; + foreach ($aModulesToCompile as $oModule) { + if ($oModule instanceof MFDeltaModule) { + // Just before loading the delta, let's save an image of the datamodel + // in case there is no delta the operation will be done after the end of the loop + $oFactory->SaveToFile(utils::GetDataPath().'datamodel-'.$this->sBuildEnv.'.xml'); + } + $oFactory->LoadModule($oModule); + } + + if (!is_null($oModule) && ($oModule instanceof MFDeltaModule)) { + // A delta was loaded, let's save a second copy of the datamodel + $oFactory->SaveToFile(utils::GetDataPath().'datamodel-'.$this->sBuildEnv.'-with-delta.xml'); + } else { + // No delta was loaded, let's save the datamodel now + $oFactory->SaveToFile(utils::GetDataPath().'datamodel-'.$this->sBuildEnv.'.xml'); + } + + $sBuildDir = APPROOT.'env-'.$this->sBuildEnv; + self::MakeDirSafe($sBuildDir); + $bSkipTempDir = ($this->sFinalEnv != $this->sBuildEnv); // No need for a temporary directory if sBuildEnv is already a temporary directory + $oMFCompiler = new MFCompiler($oFactory, $this->sFinalEnv); + $oMFCompiler->Compile($sBuildDir, null, $bUseSymLinks, $bSkipTempDir); + + MetaModel::ResetAllCaches($this->sBuildEnv); + + return array_keys($aModulesToCompile); + } + + /** + * @param array $aRemovedExtensionCodes + * @param array $aSelectedModules + * @param string $sSourceDir + * @param string $sExtensionDir + * @param boolean $bUseSymbolicLinks + * + * @return void + * @throws \ConfigException + * @throws \CoreException + * + */ + public function DoCompile(array $aRemovedExtensionCodes, array $aSelectedModules, string $sSourceDir, string $sExtensionDir, bool $bUseSymbolicLinks = false): void + { + SetupLog::Info('Compiling data model.'); + + $sEnvironment = $this->sBuildEnv; + $sBuildPath = $this->GetBuildDir(); + + $sSourcePath = APPROOT.$sSourceDir; + $aDirsToScan = [$sSourcePath]; + $sExtensionsPath = APPROOT.$sExtensionDir; + if (is_dir($sExtensionsPath)) { + // if the extensions dir exists, scan it for additional modules as well + $aDirsToScan[] = $sExtensionsPath; + } + $sExtraPath = APPROOT.'/data/'.$sEnvironment.'-modules/'; + if (is_dir($sExtraPath)) { + // if the extra dir exists, scan it for additional modules as well + $aDirsToScan[] = $sExtraPath; + } + + if (!is_dir($sSourcePath)) { + $sErrorMessage = "Failed to find the source directory '$sSourcePath', please check the rights of the web server"; + $e = new CoreException($sErrorMessage); + IssueLog::Exception($sErrorMessage, $e); + throw $e; + } + + if (!is_dir($sBuildPath)) { + if (!mkdir($sBuildPath)) { + $sErrorMessage = "Failed to create directory '$sBuildPath', please check the rights of the web server"; + $e = new CoreException($sErrorMessage); + IssueLog::Exception($sErrorMessage, $e); + throw $e; + } else { + // adjust the rights if and only if the directory was just created + // owner:rwx user/group:rx + chmod($sBuildPath, 0755); + } + } elseif ($this->IsInItop($sBuildPath)) { + // If the directory is under the root folder - as expected - let's clean-it before compiling + SetupUtils::tidydir($sBuildPath); + } + + $oExtensionsMap = new iTopExtensionsMap(ITOP_DEFAULT_ENV, $aDirsToScan); + // Removed modules are stored as static for FindModules() + $oExtensionsMap->DeclareExtensionAsRemoved($aRemovedExtensionCodes); + + // Check that all the extensions have a code + foreach ($oExtensionsMap->GetAllExtensions() as $oExtension) { + if (empty($oExtension->sCode)) { + $sExtensionLabel = !empty($oExtension->sLabel) ? $oExtension->sLabel : $oExtension->sSourceDir; + $sErrorMessage = sprintf('Extension "%s" cannot be installed: Missing extension code', $sExtensionLabel); + $e = new CoreException($sErrorMessage); + IssueLog::Exception($sErrorMessage, $e); + throw $e; + } + } + + $oFactory = new ModelFactory($aDirsToScan); + + $oDictModule = new MFDictModule('dictionaries', 'iTop Dictionaries', APPROOT.'dictionaries'); + $oFactory->LoadModule($oDictModule); + + $sDeltaFile = APPROOT.'core/datamodel.core.xml'; + if (file_exists($sDeltaFile)) { + $oCoreModule = new MFCoreModule('core', 'Core Module', $sDeltaFile); + $oFactory->LoadModule($oCoreModule); + } + $sDeltaFile = APPROOT.'application/datamodel.application.xml'; + if (file_exists($sDeltaFile)) { + $oApplicationModule = new MFCoreModule('application', 'Application Module', $sDeltaFile); + $oFactory->LoadModule($oApplicationModule); + } + + $aModules = $oFactory->FindModules(); + + foreach ($aModules as $oModule) { + $sModule = $oModule->GetName(); + if (in_array($sModule, $aSelectedModules)) { + $oFactory->LoadModule($oModule); + } + } + + // Dump the "reference" model, just before loading any actual delta + $oFactory->SaveToFile(utils::GetDataPath().'datamodel-'.$sEnvironment.'.xml'); + + $sDeltaFile = utils::GetDataPath().$sEnvironment.'.delta.xml'; + if (file_exists($sDeltaFile)) { + $oDelta = new MFDeltaModule($sDeltaFile); + $oFactory->LoadModule($oDelta); + $oFactory->SaveToFile(utils::GetDataPath().'datamodel-'.$sEnvironment.'-with-delta.xml'); + } + + $oMFCompiler = new MFCompiler($oFactory, $sEnvironment); + $oMFCompiler->Compile($sBuildPath, null, $bUseSymbolicLinks, false, false); + SetupLog::Info("Data model successfully compiled to '$sBuildPath'."); + + $sCacheDir = APPROOT.'/data/cache-'.$sEnvironment.'/'; + SetupUtils::builddir($sCacheDir); + SetupUtils::tidydir($sCacheDir); + + // Set an "Instance UUID" identifying this machine based on a file located in the data directory + $sInstanceUUIDFile = utils::GetDataPath().'instance.txt'; + SetupUtils::builddir(utils::GetDataPath()); + if (!file_exists($sInstanceUUIDFile)) { + $sInstanceUUID = utils::CreateUUID('filesystem'); + file_put_contents($sInstanceUUIDFile, $sInstanceUUID); + } + } + + /** + * @param \Config $oConfig + * @param string $sBackupFileFormat + * @param string $sSourceConfigFile + * @param string|null $sMySQLBinDir + * + * @throws \BackupException + * @throws \CoreException + * @throws \MySQLException + * @since 2.5.0 uses a {@link Config} object to store DB parameters + */ + public function Backup(Config $oConfig, string $sBackupFileFormat, string $sSourceConfigFile, ?string $sMySQLBinDir = null): void + { + $oBackup = new SetupDBBackup($oConfig); + $sTargetFile = $oBackup->MakeName($sBackupFileFormat); + if (!empty($sMySQLBinDir)) { + $oBackup->SetMySQLBinDir($sMySQLBinDir); + } + + CMDBSource::InitFromConfig($oConfig); + $oBackup->CreateCompressedBackup($sTargetFile, $sSourceConfigFile); + } + + /** + * @param \Config $oConfig + * @return void + */ + public function EnterMaintenanceMode(Config $oConfig) + { + SetupUtils::EnterMaintenanceMode($oConfig); + } + + public function EnterReadOnlyMode(Config $oConfig) + { + if ($this->GetFinalEnv() != 'production') { + return; + } + + if (SetupUtils::IsInReadOnlyMode()) { + return; + } + + SetupUtils::EnterReadOnlyMode($oConfig); + } + + public function ExitMaintenanceMode(): void + { + if (SetupUtils::IsInMaintenanceMode()) { + SetupUtils::ExitMaintenanceMode(); + } + } + + public function ExitReadOnlyMode() + { + if ($this->GetFinalEnv() != 'production') { + return; + } + + if (!SetupUtils::IsInReadOnlyMode()) { + return; + } + + SetupUtils::ExitReadOnlyMode(); + } + + public function GetFinalEnv(): string + { + return $this->sFinalEnv; + } + + protected function IsInItop(string $sPath): bool + { + $sFileRealPath = realpath($sPath); + if ($sFileRealPath === false) { + return false; + } + + $sRealBasePath = realpath(APPROOT); // avoid problems when having '/' on Windows for example + if (!self::StartsWith($sFileRealPath, $sRealBasePath)) { + return false; + } + + return true; + } + + protected static function StartsWith(string $sHaystack, string $sNeedle): bool + { + if (strlen($sNeedle) > strlen($sHaystack)) { + return false; + } + + return substr_compare($sHaystack, $sNeedle, 0, strlen($sNeedle)) === 0; + } + + /** + * @param string $sSourceEnv + * @param array $aSearchDirs : module/extension dirs to load if they are included in choices + * + * @return array| null + * @throws \ConfigException + * @throws \CoreException + * @throws \ModuleInstallationException + */ + protected function GetModulesToLoad(string $sSourceEnv, array $aSearchDirs): ?array + { + if (is_null($this->GetExtensionMap())) { + return null; + } + + $oSourceConfig = new Config(utils::GetConfigFilePath($sSourceEnv)); + + $aChoices = $this->GetExtensionMap()->GetChoicesFromDatabase($oSourceConfig); + return $this->GetModulesToLoadFromChoices($oSourceConfig, $aChoices, $aSearchDirs); + } + + /** + * Return modules based on installation choices+package +* @param \Config $oConfig +* @param array|bool $aChoices +* @param array $aSearchDirs +* @return array|null +* @throws \ModuleInstallationException + */ + public function GetModulesToLoadFromChoices(Config $oConfig, array|bool $aChoices, array $aSearchDirs): ?array + { + if (false === $aChoices) { + return null; + } + + $sSourceDir = $oConfig->Get('source_dir'); + + $sInstallFilePath = APPROOT.$sSourceDir.'/installation.xml'; + if (! is_file($sInstallFilePath)) { + $sInstallFilePath = null; + } + + $aExtensionDirs = []; + foreach ($this->GetExtensionMap()->GetAllExtensions() as $oExtension) { + if ($oExtension->bMarkedAsChosen && is_dir($oExtension->sSourceDir)) { + $aExtensionDirs [] = $oExtension->sSourceDir; + } + } + + SetupLog::Info(__METHOD__, null, ['ext_dirs' => $aExtensionDirs]); + $aModuleIdsToLoad = InstallationChoicesToModuleConverter::GetInstance()->GetModules($aChoices, $aSearchDirs, $sInstallFilePath, $aExtensionDirs); + $aModulesToLoad = []; + foreach ($aModuleIdsToLoad as $sModuleId) { + $oModule = new Module($sModuleId); + $sModuleName = $oModule->GetModuleName(); + $aModulesToLoad[] = $sModuleName; + } + + return $aModulesToLoad; + } + + /** + * Replace target for links in sToScan from sSource to sDest + * + * @param string $sToScan where to search for symlinks + * @param string $sSource part to replace in the link target + * @param string $sDest replacement in the link target + * + * @return void + */ + private function RerouteSymlinks(string $sToScan, string $sSource, string $sDest) + { + if (is_dir($sToScan)) { + $aFiles = scandir($sToScan); + if (sizeof($aFiles) > 0) { + foreach ($aFiles as $sFile) { + if ($sFile == '.' || $sFile == '..' || $sFile == '.svn' || $sFile == '.git') { + // Skip + continue; + } + $this->RerouteSymlinks($sToScan.'/'.$sFile, $sSource, $sDest); + } + } + } elseif (is_link($sToScan)) { + $sLinkPath = readlink($sToScan); + $sLinkPath = str_replace($sSource, $sDest, $sLinkPath); + unlink($sToScan); + symlink($sLinkPath, $sToScan); + } + } +} diff --git a/setup/sequencers/ApplicationInstallSequencer.php b/setup/sequencers/ApplicationInstallSequencer.php new file mode 100644 index 0000000000..d62136aef7 --- /dev/null +++ b/setup/sequencers/ApplicationInstallSequencer.php @@ -0,0 +1,213 @@ + 'Log parameters', + 'backup' => 'Performing a backup of the database', + 'migrate-before' => 'Migrate data before database upgrade', + 'db-schema' => 'Updating database schema', + 'migrate-after' => 'Migrate data after database upgrade', + 'after-db-create' => 'Load data after database create', + 'load-data' => 'Loading data', + 'create-config' => 'Creating the configuration File', + 'commit' => 'Finalize', + ]; + protected const SUCCESS_LABELS = [ + 'log-parameters' => 'Parameters logged', + 'backup' => 'Database backup completed', + 'migrate-before' => 'Pre-upgrade data migration completed', + 'db-schema' => 'Database schema updated', + 'migrate-after' => 'Post-upgrade data migration completed', + 'after-db-create' => 'Post-creation data loaded', + 'load-data' => 'Data loaded', + 'create-config' => 'Configuration file created', + ]; + + /** + * @inherit + */ + public function ExecuteStep($sStep = '', $sInstallComment = null): array + { + $fStart = microtime(true); + try { + /** + * @since 3.2.0 move the ContextTag init at the very beginning of the method + * @noinspection PhpUnusedLocalVariableInspection + */ + $oContextTag = new ContextTag(ContextTag::TAG_SETUP); + SetupLog::Info("##### STEP {$sStep} start"); + $this->oRunTimeEnvironment->EnterReadOnlyMode($this->GetConfig()); + switch ($sStep) { + case '': + return $this->ComputeNextStep($sStep); + + case 'log-parameters': + if (array_key_exists($sStep, $this->oParams->Get('optional_steps', []))) { + $this->DoLogParameters(); + } + return $this->ComputeNextStep($sStep); + + case 'backup': + if (array_key_exists($sStep, $this->oParams->Get('optional_steps', []))) { + $aBackupOptions = $this->oParams->Get('optional_steps')['backup']; + // __DB__-%Y-%m-%d + $sDestination = $aBackupOptions['destination']; + $sSourceConfigFile = $aBackupOptions['configuration_file']; + $sMySQLBinDir = $this->oParams->Get('mysql_bindir', null); + $this->oRunTimeEnvironment->Backup($this->GetConfig(), $sDestination, $sSourceConfigFile, $sMySQLBinDir); + } + + return $this->ComputeNextStep($sStep); + + case 'migrate-before': + $this->oRunTimeEnvironment->EnterMaintenanceMode($this->GetConfig()); + if (array_key_exists($sStep, $this->oParams->Get('optional_steps', []))) { + $this->oRunTimeEnvironment->MigrateDataBeforeUpdateStructure($this->oParams->Get('mode'), $this->GetConfig()); + } + return $this->ComputeNextStep($sStep); + + case 'db-schema': + $aSelectedModules = $this->oParams->Get('selected_modules', []); + $this->DoUpdateDBSchema($this->GetConfig(), $aSelectedModules); + return $this->ComputeNextStep($sStep); + + case 'migrate-after': + if (array_key_exists($sStep, $this->oParams->Get('optional_steps', []))) { + $this->oRunTimeEnvironment->MigrateDataAfterUpdateStructure($this->oParams->Get('mode'), $this->GetConfig()); + } + return $this->ComputeNextStep($sStep); + + case 'after-db-create': + $aAdminParams = $this->oParams->Get('admin_account'); + $aSelectedModules = $this->oParams->Get('selected_modules', []); + $sMode = $this->oParams->Get('mode'); + $this->oRunTimeEnvironment->AfterDBCreate($this->GetConfig(), $sMode, $aSelectedModules, $aAdminParams); + return $this->ComputeNextStep($sStep); + + case 'load-data': + $aSelectedModules = $this->oParams->Get('selected_modules', []); + $bSampleData = ($this->oParams->Get('sample_data', 0) == 1); + $this->oRunTimeEnvironment->DoLoadData($this->GetConfig(), $bSampleData, $aSelectedModules); + return $this->ComputeNextStep($sStep); + + case 'create-config': + $sDataModelVersion = $this->oParams->Get('datamodel_version', '0.0.0'); + $aSelectedModuleCodes = $this->oParams->Get('selected_modules', []); + $aSelectedExtensionCodes = $this->oParams->Get('selected_extensions', []); + $this->oRunTimeEnvironment->DoCreateConfig( + $this->GetConfig(), + $sDataModelVersion, + $aSelectedModuleCodes, + $aSelectedExtensionCodes, + $sInstallComment, + $this->sSourceDesc + ); + return $this->ComputeNextStep($sStep); + + case 'commit': + $this->oRunTimeEnvironment->Commit(); + $this->oRunTimeEnvironment->ExitReadOnlyMode(); + $this->oRunTimeEnvironment->ExitMaintenanceMode(); + return $this->GetNextStep('', 'Completed', 100); + + default: + return $this->GetNextStep('', "Unknown setup step '$sStep'.", 100, '', '', self::ERROR); + } + } catch (Exception $e) { + SetupLog::Exception("$sStep failed", $e); + $aResult = $this->GetNextStep('', '', 100, $e->getMessage(), '', self::ERROR); + $aResult['error_code'] = $e->getCode(); + return $aResult; + } finally { + $fDuration = round(microtime(true) - $fStart, 2); + SetupLog::Info("##### STEP {$sStep} duration: {$fDuration}s"); + } + } + + /** + * @param \Config $oConfig + * @param $aSelectedModules + * + * @throws \CoreException + * @throws \DictExceptionUnknownLanguage + * @throws \MySQLException + * @throws \MySQLHasGoneAwayException + * @throws \OQLException + */ + protected function DoUpdateDBSchema(Config $oConfig, $aSelectedModules) + { + $sTargetEnvironment = $this->oRunTimeEnvironment->GetBuildEnv(); + $aParamValues = $this->oParams->GetParamForConfigArray(); + + SetupLog::Info("Update Database Schema for environment '$sTargetEnvironment'."); + $sMode = $aParamValues['mode']; + + $this->oRunTimeEnvironment->UpdateDBSchema($oConfig, $sMode, $aSelectedModules); + + $this->oRunTimeEnvironment->SetDbUUID(); + + SetupLog::Info("Database Schema Successfully Updated for environment '$sTargetEnvironment'."); + } + + public function GetStepNames(): array + { + $aStepNames = [ '']; + foreach (['log-parameters', 'backup', 'migrate-before'] as $sStepName) { + if (array_key_exists($sStepName, $this->oParams->Get('optional_steps', []))) { + $aStepNames [] = $sStepName; + } + } + $aStepNames [] = 'db-schema'; + if (array_key_exists('migrate-after', $this->oParams->Get('optional_steps', []))) { + $aStepNames [] = 'migrate-after'; + } + + $aOthers = [ + 'after-db-create', + 'load-data', + 'create-config', + 'commit', + ]; + $aStepNames = array_merge($aStepNames, $aOthers); + return $aStepNames; + } +} diff --git a/setup/sequencers/DataAuditSequencer.php b/setup/sequencers/DataAuditSequencer.php new file mode 100644 index 0000000000..74f305e188 --- /dev/null +++ b/setup/sequencers/DataAuditSequencer.php @@ -0,0 +1,138 @@ + 'Copying data model files', + 'compile' => 'Compiling the data model', + 'setup-audit' => 'Checking data consistency with the new data model', + 'complete' => 'Check Completed', + ]; + protected const SUCCESS_LABELS = [ + 'copy' => 'Data model files copied', + 'compile' => 'Data model compilation completed', + 'setup-audit' => 'Data consistency check completed', + 'complete' => 'All checks completed', + ]; + + /** + * @inherit + */ + public function ExecuteStep($sStep = '', $sInstallComment = null): array + { + $fStart = microtime(true); + try { + /** + * @since 3.2.0 move the ContextTag init at the very beginning of the method + * @noinspection PhpUnusedLocalVariableInspection + */ + $oContextTag = new ContextTag(ContextTag::TAG_SETUP); + SetupLog::Info("##### STEP {$sStep} start"); + switch ($sStep) { + case '': + return $this->ComputeNextStep($sStep); + + case 'copy': + $this->oRunTimeEnvironment->CopySetupFiles(); + return $this->ComputeNextStep($sStep); + + case 'compile': + $aSelectedModules = $this->oParams->Get('selected_modules', []); + $sSourceDir = $this->oParams->Get('source_dir', 'datamodels/latest'); + $sExtensionDir = $this->oParams->Get('extensions_dir', 'extensions'); + $aRemovedExtensionCodes = $this->oParams->Get('removed_extensions', []); + $bUseSymbolicLinks = $this->oParams->Get('use_symbolic_links', null) === 'on'; + MetaModel::ResetAllCaches($this->oRunTimeEnvironment->GetBuildEnv()); + $this->oRunTimeEnvironment->DoCompile( + $aRemovedExtensionCodes, + $aSelectedModules, + $sSourceDir, + $sExtensionDir, + $bUseSymbolicLinks + ); + return $this->ComputeNextStep($sStep); + + case 'setup-audit': + $this->oRunTimeEnvironment->DataToCleanupAudit(); + return $this->ComputeNextStep($sStep); + + case 'complete': + return $this->GetNextStep('', 'Completed', 100); + + default: + return $this->GetNextStep('', "Unknown setup step '$sStep'.", 100, '', '', self::ERROR); + + } + } catch (Exception $e) { + SetupLog::Exception("$sStep failed", $e); + $aResult = $this->GetNextStep('', '', 100, $e->getMessage(), '', self::ERROR); + $aResult['error_code'] = $e->getCode(); + return $aResult; + } finally { + $fDuration = round(microtime(true) - $fStart, 2); + SetupLog::Info("##### STEP {$sStep} duration: {$fDuration}s"); + } + } + + protected function IsDataAuditRequired(): bool + { + if (! array_key_exists('setup-audit', $this->oParams->Get('optional_steps', []))) { + return false; + } + + if ('install' === $this->oParams->Get('mode')) { + return false; + } + + $aInstalledInfo = $this->oRunTimeEnvironment->GetApplicationVersion($this->GetConfig()); + $sInstalledVersion = $aInstalledInfo['product_version']; + + if ($sInstalledVersion !== ITOP_VERSION_FULL) { + return false; + } + + $sFinalEnvDir = APPROOT.'env-'.$this->oRunTimeEnvironment->GetFinalEnv(); + return is_dir($sFinalEnvDir); + } + + public function GetStepNames(): array + { + $aStepNames = ['']; + if (array_key_exists('copy', $this->oParams->Get('optional_steps', []))) { + $aStepNames[] = 'copy'; + } + $aStepNames[] = 'compile'; + if ($this->IsDataAuditRequired()) { + $aStepNames[] = 'setup-audit'; + } + $aStepNames[] = 'complete'; + + return $aStepNames; + } +} diff --git a/setup/sequencers/StepSequencer.php b/setup/sequencers/StepSequencer.php new file mode 100644 index 0000000000..4967212de0 --- /dev/null +++ b/setup/sequencers/StepSequencer.php @@ -0,0 +1,236 @@ +Get('target_env', 'production'); + $this->oRunTimeEnvironment = new RunTimeEnvironment($sEnvironment, false); + } else { + $this->oRunTimeEnvironment = $oRunTimeEnvironment; + } + + $this->oParams = $oParams; + utils::SetConfig($this->GetConfig()); + $this->sSourceDesc = $sSourceDesc; + } + + public function LogStep($sStep, $aResult) + { + $this->aStepsHistory[] = ['step' => $sStep, 'result' => $aResult]; + } + public function GetHistory() + { + return $this->aStepsHistory; + } + + /** + * Runs all the installation steps in one go and directly outputs + * some information about the progress and the success of the various + * sequential steps. + * + * @param bool $bVerbose + * @param string|null $sMessage + * @param string|null $sComment + * + * @return boolean True if the installation was successful, false otherwise + */ + public function ExecuteAllSteps(bool $bVerbose = true, ?string &$sMessage = null, ?string $sComment = null) + { + $sStep = ''; + $sStepLabel = ''; + $iOverallStatus = self::OK; + do { + + if ($bVerbose) { + if ($sStep != '') { + echo "$sStepLabel\n"; + echo "Executing '$sStep'\n"; + } else { + echo "Starting...\n"; + } + } + $aRes = $this->ExecuteStep($sStep, $sComment); + $this->LogStep($sStep, $aRes); + $sStep = $aRes['next-step']; + $sStepLabel = $aRes['next-step-label']; + $sMessage = $aRes['message']; + if ($bVerbose) { + switch ($aRes['status']) { + case self::OK: + echo "Ok. ".$aRes['percentage-completed']." % done.\n"; + break; + + case self::ERROR: + $iOverallStatus = self::ERROR; + echo "Error: ".$aRes['message']."\n"; + break; + + case self::WARNING: + $iOverallStatus = self::WARNING; + echo "Warning: ".$aRes['message']."\n"; + echo $aRes['percentage-completed']." % done.\n"; + break; + + case self::INFO: + echo "Info: ".$aRes['message']."\n"; + echo $aRes['percentage-completed']." % done.\n"; + break; + } + } else { + switch ($aRes['status']) { + case self::ERROR: + $iOverallStatus = self::ERROR; + break; + case self::WARNING: + $iOverallStatus = self::WARNING; + break; + } + } + } while (($aRes['status'] != self::ERROR) && ($aRes['next-step'] != '')); + + return ($iOverallStatus == self::OK); + } + + protected function GetNextStep(string $sNextStep, string $sNextStepLabel, int $iPercentComplete, string $sMessage = '', string $sPrevStepSuccessMessage = '', int $iStatus = self::OK): array + { + return [ + 'status' => $iStatus, + 'message' => $sMessage, + 'next-step' => $sNextStep, + 'next-step-label' => $sNextStepLabel, + 'prev-step-success-message' => $sPrevStepSuccessMessage, + 'percentage-completed' => $iPercentComplete, + ]; + } + + protected function DoLogParameters($sPrefix = 'install-', $sOperation = 'Installation') + { + // Log the parameters... + $oDoc = new DOMDocument('1.0', 'UTF-8'); + $oDoc->preserveWhiteSpace = false; + $oDoc->formatOutput = true; + $this->oParams->ToXML($oDoc, null, 'installation'); + $sXML = $oDoc->saveXML(); + $sSafeXml = preg_replace('|([^<]*)|', '**removed**', $sXML); + SetupLog::Info('======= '.$sOperation." starts =======\nParameters:\n$sSafeXml\n"); + + // Save the response file as a stand-alone file as well + $sFileName = $sPrefix.date('Y-m-d'); + $index = 0; + while (file_exists(APPROOT.'log/'.$sFileName.'.xml')) { + $index++; + $sFileName = $sPrefix.date('Y-m-d').'-'.$index; + } + file_put_contents(APPROOT.'log/'.$sFileName.'.xml', $sSafeXml); + } + + /** + * @return \Config + * @throws \ConfigException + * @throws \CoreException + */ + protected function GetConfig() + { + if (! is_null($this->oTestConfig)) { + return $this->oTestConfig; + } + + // Caching config here is a bad idea, the first config loaded does not contain module settings + $sTargetEnvironment = $this->oRunTimeEnvironment->GetBuildEnv(); + $sConfigFile = APPCONF.$sTargetEnvironment.'/'.ITOP_CONFIG_FILE; + try { + if (file_exists($sConfigFile)) { + $oConfig = new Config($sConfigFile); + } else { + $oConfig = new Config(); + } + + $oConfig->Set('access_mode', ACCESS_FULL); + } catch (Exception $e) { + SetupLog::Exception("Setup error", $e); + throw $e; + } + + $aParamValues = $this->oParams->GetParamForConfigArray(); + $oConfig->UpdateFromParams($aParamValues); + + return $oConfig; + } + + public function GetStepAfterWithPercent($sCurrentStep): array + { + $aAllStepNames = $this->GetStepNames(); + $iKey = array_search($sCurrentStep, $aAllStepNames); + $iNextStepIndex = $iKey + 1; + $sNextStep = $aAllStepNames[$iNextStepIndex] ?? ''; + return [$sNextStep, $this->ComputePercent($aAllStepNames, $iNextStepIndex)]; + } + + public function ComputePercent(array $aAllStepNames, $iKey): int + { + $iCount = count($aAllStepNames); + if ($iKey >= $iCount) { + return 100; + } + + $iRes = 100 * $iKey / $iCount; + return (int) $iRes; + } + + protected function ComputeNextStep(string $sCurrentStep, string $sMessage = ''): array + { + [$sNextStep, $iPercent] = $this->GetStepAfterWithPercent($sCurrentStep); + $sLabel = static::LABELS[$sNextStep] ?? ''; + $sCurrentStepSuccessMessage = static::SUCCESS_LABELS[$sCurrentStep] ?? ''; + return $this->GetNextStep($sNextStep, $sLabel, $iPercent, $sMessage, $sCurrentStepSuccessMessage); + } + + abstract public function GetStepNames(): array; + + /** + * Executes the next step of the installation and reports about the progress + * and the next step to perform + * + * @param string $sStep The identifier of the step to execute + * @param string|null $sInstallComment + * + * @return array (status => , message => , percentage-completed => , next-step => , next-step-label => ) + */ + abstract public function ExecuteStep($sStep = '', $sInstallComment = null): array; +} diff --git a/setup/setup.js b/setup/setup.js index a7d7402601..c7917b7497 100644 --- a/setup/setup.js +++ b/setup/setup.js @@ -25,21 +25,17 @@ function WizardAsyncAction(sActionCode, oParams, OnErrorFunction) function WizardUpdateButtons() { - if (CanMoveForward()) - { + if (CanMoveForward()) { $("#btn_next").prop('disabled', false); } - else - { + else { $("#btn_next").prop('disabled', true); } - if (CanMoveBackward()) - { + if (CanMoveBackward()) { $("#btn_back").prop('disabled', false); } - else - { + else { $("#btn_back").prop('disabled', true); } } diff --git a/setup/setuputils.class.inc.php b/setup/setuputils.class.inc.php index b6ce04ef12..776861168d 100644 --- a/setup/setuputils.class.inc.php +++ b/setup/setuputils.class.inc.php @@ -58,7 +58,7 @@ class CheckResult /** * @param \CheckResult[] $aResults - * @param string[] $aCheckResultSeverities list of CheckResult object severities to keep + * @param array $aCheckResultSeverities list of CheckResult object severities to keep * * @return \CheckResult[] only elements that have one of the passed severity * @@ -254,32 +254,23 @@ class SetupUtils if (!utils::IsModeCLI()) { $sUploadTmpDir = self::GetUploadTmpDir(); - if (empty($sUploadTmpDir)) { - $sUploadTmpDir = '/tmp'; - $aResult[] = new CheckResult( - CheckResult::WARNING, - "Temporary directory for files upload is not defined (upload_tmp_dir), assuming that $sUploadTmpDir is used." - ); - } // check that the upload directory is indeed writable from PHP - if (!empty($sUploadTmpDir)) { - if (!file_exists($sUploadTmpDir)) { + if (!file_exists($sUploadTmpDir)) { + $aResult[] = new CheckResult( + CheckResult::ERROR, + "Temporary directory for files upload ($sUploadTmpDir) does not exist or cannot be read by PHP." + ); + } else { + if (!is_writable($sUploadTmpDir)) { $aResult[] = new CheckResult( CheckResult::ERROR, - "Temporary directory for files upload ($sUploadTmpDir) does not exist or cannot be read by PHP." + "Temporary directory for files upload ($sUploadTmpDir) is not writable." ); } else { - if (!is_writable($sUploadTmpDir)) { - $aResult[] = new CheckResult( - CheckResult::ERROR, - "Temporary directory for files upload ($sUploadTmpDir) is not writable." - ); - } else { - $aResult[] = new CheckResult( - CheckResult::TRACE, - "Info - Temporary directory for files upload ($sUploadTmpDir) is writable." - ); - } + $aResult[] = new CheckResult( + CheckResult::TRACE, + "Info - Temporary directory for files upload ($sUploadTmpDir) is writable." + ); } } } @@ -467,6 +458,7 @@ class SetupUtils ); $sPhpNextMinVersion = self::PHP_NEXT_MIN_VERSION; // mandatory before PHP 5.5 (arbitrary expressions), keeping compat because we're in the setup ! + // @phpstan-ignore empty.variable if (!empty($sPhpNextMinVersion)) { if (version_compare($sPhpVersion, self::PHP_NEXT_MIN_VERSION, '>=')) { $aResult[] = new CheckResult( @@ -518,7 +510,7 @@ class SetupUtils } require_once(APPROOT.'setup/modulediscovery.class.inc.php'); try { - ModuleDiscovery::GetAvailableModules($aDirsToScan, true, $aSelectedModules); + ModuleDiscovery::GetModulesOrderedByDependencies($aDirsToScan, true, $aSelectedModules); } catch (Exception $e) { $aResult[] = new CheckResult(CheckResult::ERROR, $e->getMessage()); } @@ -599,7 +591,7 @@ class SetupUtils // create and test destination location // $sDestDir = dirname($sDBBackupPath); - setuputils::builddir($sDestDir); + SetupUtils::builddir($sDestDir); if (!is_dir($sDestDir)) { $aResult[] = new CheckResult(CheckResult::ERROR, "$sDestDir does not exist and could not be created."); } @@ -826,6 +818,11 @@ class SetupUtils } } + public static function CopyFile(string $sSource, string $sDest, bool $bUseSymbolicLinks = false): bool + { + return self::copydir($sSource, $sDest, $bUseSymbolicLinks); + } + /** * Helper to copy a directory to a target directory, skipping .SVN files (for developer's comfort!) * Returns true if successful @@ -835,11 +832,13 @@ class SetupUtils * @return bool * @throws Exception */ - public static function copydir($sSource, $sDest, $bUseSymbolicLinks = false) + public static function copydir(string $sSource, string $sDest, bool $bUseSymbolicLinks = false): bool { if (is_dir($sSource)) { if (!is_dir($sDest)) { mkdir($sDest, 0777 /* Default */, true); + } else { + SetupUtils::tidydir($sDest); } $aFiles = scandir($sSource); if (sizeof($aFiles) > 0) { @@ -848,25 +847,19 @@ class SetupUtils // Skip continue; } - - if (is_dir($sSource.'/'.$sFile)) { + $sSourcePath = $sSource.'/'.$sFile; + $sDestPath = $sDest.'/'.$sFile; + if (is_dir($sSourcePath)) { // Recurse - self::copydir($sSource.'/'.$sFile, $sDest.'/'.$sFile, $bUseSymbolicLinks); + self::copydir($sSourcePath, $sDestPath, $bUseSymbolicLinks); + } elseif (is_link($sSourcePath)) { + $sLinkPath = readlink($sSourcePath); + symlink($sLinkPath, $sDestPath); } else { if ($bUseSymbolicLinks) { - if (function_exists('symlink')) { - if (file_exists($sDest.'/'.$sFile)) { - unlink($sDest.'/'.$sFile); - } - symlink($sSource.'/'.$sFile, $sDest.'/'.$sFile); - } else { - throw(new Exception("Error, cannot *copy* '$sSource/$sFile' to '$sDest/$sFile' using symbolic links, 'symlink' is not supported on this system.")); - } + symlink($sSourcePath, $sDestPath); } else { - if (is_link($sDest.'/'.$sFile)) { - unlink($sDest.'/'.$sFile); - } - copy($sSource.'/'.$sFile, $sDest.'/'.$sFile); + copy($sSourcePath, $sDestPath); } } } @@ -874,11 +867,10 @@ class SetupUtils return true; } elseif (is_file($sSource)) { if ($bUseSymbolicLinks) { - if (function_exists('symlink')) { - return symlink($sSource, $sDest); - } else { - throw(new Exception("Error, cannot *copy* '$sSource' to '$sDest' using symbolic links, 'symlink' is not supported on this system.")); - } + return symlink($sSource, $sDest); + } elseif (is_link($sSource)) { + $sLinkPath = readlink($sSource); + return symlink($sLinkPath, $sDest); } else { return copy($sSource, $sDest); } @@ -932,7 +924,7 @@ class SetupUtils $aResult['found'] = true; } elseif (file_exists($sDir.'/conf/production/config-itop.php')) { $sSourceDir = $sDir; - $sSourceEnvironment = 'production'; + $sSourceEnvironment = ITOP_DEFAULT_ENV; $sConfigFile = $sDir.'/conf/production/config-itop.php'; $aResult['found'] = true; } @@ -1368,6 +1360,7 @@ EOF ); $sMySqlNextMinVersion = self::MYSQL_NEXT_MIN_VERSION; // mandatory before PHP 5.5 (arbitrary expressions), keeping compat because we're in the setup ! + // @phpstan-ignore empty.variable if (!empty($sMySqlNextMinVersion)) { if (version_compare($sDBVersion, self::MYSQL_NEXT_MIN_VERSION, '>=')) { $aResult['checks'][] = new CheckResult( @@ -1555,17 +1548,8 @@ JS return $sHtml; } - /** - * @param \WizardController $oWizard - * @param bool $bAbortOnMissingDependency ... - * @param array $aModulesToLoad List of modules to search for, defaults to all if ommitted - * - * @return array - * @throws Exception - */ - public static function AnalyzeInstallation($oWizard, $bAbortOnMissingDependency = false, $aModulesToLoad = null) + public static function GetConfig(WizardController $oWizard) { - require_once(APPROOT.'/setup/moduleinstaller.class.inc.php'); $oConfig = new Config(); $sSourceDir = $oWizard->GetParameter('source_dir', ''); @@ -1579,8 +1563,28 @@ JS $aParamValues = $oWizard->GetParamForConfigArray(); $aParamValues['source_dir'] = $sRelativeSourceDir; - $oConfig->UpdateFromParams($aParamValues, null); - $aDirsToScan = [$sSourceDir]; + $oConfig->UpdateFromParams($aParamValues); + + return $oConfig; + } + + /** + * @param \WizardController $oWizard + * @param bool $bAbortOnMissingDependency ... + * @param array $aModulesToLoad List of modules to search for, defaults to all if ommitted + * + * @return array + * @throws Exception + */ + public static function AnalyzeInstallation($oWizard, $bAbortOnMissingDependency = false, $aModulesToLoad = null, ?Config $oConfig = null) + { + require_once(APPROOT.'/setup/moduleinstaller.class.inc.php'); + + if (is_null($oConfig)) { + $oConfig = self::GetConfig($oWizard); + } + + $aDirsToScan = [$oWizard->GetParameter('source_dir', '')]; if (is_dir(APPROOT.'extensions')) { $aDirsToScan[] = APPROOT.'extensions'; @@ -1593,6 +1597,10 @@ JS $aDirsToScan[] = $sExtraDir; } $oProductionEnv = new RunTimeEnvironment(); + $aRemovedExtensionCodes = json_decode($oWizard->GetParameter('removed_extensions'), true) ?? []; + $oExtensionsMap = new iTopExtensionsMap(ITOP_DEFAULT_ENV, $aDirsToScan); + $oExtensionsMap->DeclareExtensionAsRemoved($aRemovedExtensionCodes); + $aAvailableModules = $oProductionEnv->AnalyzeInstallation($oConfig, $aDirsToScan, $bAbortOnMissingDependency, $aModulesToLoad); foreach ($aAvailableModules as $key => $aModule) { @@ -1618,7 +1626,7 @@ JS $aParamValues = $oWizard->GetParamForConfigArray(); $aParamValues['source_dir'] = ''; - $oConfig->UpdateFromParams($aParamValues, null); + $oConfig->UpdateFromParams($aParamValues); $oProductionEnv = new RunTimeEnvironment(); return $oProductionEnv->GetApplicationVersion($oConfig); @@ -1679,8 +1687,8 @@ JS * @param string $sSourceDir Relative path to the directory to check under $sBaseDir * @param $aManifest * @param array $aExcludeNames - * @param Hash $aResult Used for recursion - * @return hash Hash array ('added' => array(), 'removed' => array(), 'modified' => array()) + * @param array $aResult Used for recursion + * @return array array ('added' => array(), 'removed' => array(), 'modified' => array()) * @internal param array $aDOMManifest Array of array('path' => relative_path 'size'=> iSize, 'md5' => sHexMD5) */ public static function CheckDirAgainstManifest($sBaseDir, $sSourceDir, $aManifest, $aExcludeNames = ['.svn', '.git'], $aResult = null) @@ -1805,7 +1813,7 @@ JS /** * @param string $sInstalledVersion * @param string $sSourceDir - * @return bool|hash + * @return bool|array * @throws Exception */ public static function CheckVersion($sInstalledVersion, $sSourceDir) @@ -1993,14 +2001,7 @@ JS return; } // Use mutex to check if cron is running - $oMutex = new iTopMutex( - 'cron'.$oConfig->Get('db_name').$oConfig->Get('db_subname'), - $oConfig->Get('db_host'), - $oConfig->Get('db_user'), - $oConfig->Get('db_pwd'), - $oConfig->Get('db_tls.enabled'), - $oConfig->Get('db_tls.ca') - ); + $oMutex = self::GetCronMutex($oConfig); $iCount = 1; $iStarted = time(); $iMaxDuration = $oConfig->Get('cron_max_execution_time'); @@ -2018,6 +2019,26 @@ JS } } + /** + * @param \Config $oConfig + * + * @return \iTopMutex + * @since 3.3.0 + */ + public static function GetCronMutex(Config $oConfig): iTopMutex + { + $oMutex = new iTopMutex( + 'cron'.$oConfig->Get('db_name').$oConfig->Get('db_subname'), + $oConfig->Get('db_host'), + $oConfig->Get('db_user'), + $oConfig->Get('db_pwd'), + $oConfig->Get('db_tls.enabled'), + $oConfig->Get('db_tls.ca') + ); + + return $oMutex; + } + /** * Create and store Setup authentication token * @@ -2146,7 +2167,7 @@ class SetupInfo /** * Called by the setup process to initializes the list of selected modules. Do not call this method * from an 'auto_select' rule - * @param hash $aModules + * @param array $aModules * @return void */ public static function SetSelectedModules($aModules) diff --git a/setup/unattended-install/InstallationFileService.php b/setup/unattended-install/InstallationFileService.php index ad15466fa4..1b05151cfe 100644 --- a/setup/unattended-install/InstallationFileService.php +++ b/setup/unattended-install/InstallationFileService.php @@ -1,12 +1,12 @@ sInstallationPath = $sInstallationPath; $this->aSelectedModules = []; @@ -71,12 +71,12 @@ class InstallationFileService return $this->aAfterComputationSelectedExtensions; } - public function SetItopExtensionsMap(ItopExtensionsMap $oItopExtensionsMap): void + public function SetItopExtensionsMap(iTopExtensionsMap $oItopExtensionsMap): void { $this->oItopExtensionsMap = $oItopExtensionsMap; } - public function GetItopExtensionsMap(): ItopExtensionsMap + public function GetItopExtensionsMap(): iTopExtensionsMap { if (is_null($this->oItopExtensionsMap)) { $this->oItopExtensionsMap = new iTopExtensionsMap($this->sTargetEnvironment); @@ -259,7 +259,7 @@ class InstallationFileService { $sProductionModuleDir = APPROOT.'data/'.$this->sTargetEnvironment.'-modules/'; - $aAvailableModules = $this->GetProductionEnv()->AnalyzeInstallation(MetaModel::GetConfig(), $this->GetExtraDirs(), false, null); + $aAvailableModules = $this->GetProductionEnv()->AnalyzeInstallation(MetaModel::GetConfig(), $this->GetExtraDirs()); $this->aAutoSelectModules = []; foreach ($aAvailableModules as $sModuleId => $aModule) { @@ -287,7 +287,7 @@ class InstallationFileService public function ProcessAutoSelectModules(): void { - $oPhpExpressionEvaluator = new PhpExpressionEvaluator([], RunTimeEnvironment::STATIC_CALL_AUTOSELECT_WHITELIST); + $oPhpExpressionEvaluator = new PhpExpressionEvaluator([], ModuleFileReader::STATIC_CALL_AUTOSELECT_WHITELIST); foreach ($this->GetAutoSelectModules() as $sModuleId => $aModule) { try { diff --git a/setup/unattended-install/unattended-install.php b/setup/unattended-install/unattended-install.php index 34cf4901b0..b6362bd723 100644 --- a/setup/unattended-install/unattended-install.php +++ b/setup/unattended-install/unattended-install.php @@ -56,7 +56,7 @@ $sMode = $oParams->Get('mode'); $sTargetEnvironment = $oParams->Get('target_env', ''); if ($sTargetEnvironment == '') { - $sTargetEnvironment = 'production'; + $sTargetEnvironment = ITOP_DEFAULT_ENV; } $sXmlSetupBaseName = basename($sParamFile); @@ -82,7 +82,7 @@ if (! is_null($sInstallationXmlPath) && is_file($sInstallationXmlPath)) { $aComputedExtensions = $oInstallationFileService->GetAfterComputationSelectedExtensions(); if (! $bInstallationChoicesProvided) { $sMsg = "Computed installation choices"; - echo "$sMsg:\n".implode(',', $aComputedExtensions)."\n\n"; + echo "$sMsg:\n".implode(",\n", $aComputedExtensions)."\n\n"; SetupLog::Info($sMsg, null, $aComputedExtensions); $oParams->Set('selected_extensions', $aComputedExtensions); } @@ -97,8 +97,8 @@ if (! is_null($sInstallationXmlPath) && is_file($sInstallationXmlPath)) { $sMsg = "Modules to install listed in $sXmlSetupBaseName (selected_modules section)"; } -sort($aSelectedModules); -echo "$sMsg:\n".implode(',', $aSelectedModules)."\n\n"; +//sort($aSelectedModules); +echo "$sMsg:\n".implode(",\n", $aSelectedModules)."\n\n"; SetupLog::Info($sMsg, null, $aSelectedModules); // Configuration file @@ -218,7 +218,7 @@ if ($sMode == 'install') { //use settings from itop conf $sTargetEnvironment = $oParams->Get('target_env', ''); if ($sTargetEnvironment == '') { - $sTargetEnvironment = 'production'; + $sTargetEnvironment = ITOP_DEFAULT_ENV; } $sTargetDir = APPROOT.'env-'.$sTargetEnvironment; } @@ -271,23 +271,34 @@ $bFoundIssues = false; $bInstall = utils::ReadParam('install', true, true /* CLI allowed */); if ($bInstall) { + if (! isset($_SESSION)) { + $_SESSION = []; + } + echo "Starting the unattended installation...\n"; - $oWizard = new ApplicationInstaller($oParams); - $bRes = $oWizard->ExecuteAllSteps(); + $oWizard = new DataAuditSequencer($oParams); + $sComment = "Done by Unattended Install"; + $bRes = $oWizard->ExecuteAllSteps(sComment:$sComment); + + if ($bRes) { + $oWizard = new ApplicationInstallSequencer($oParams); + $bRes = $oWizard->ExecuteAllSteps(sComment:$sComment); + } + if (!$bRes) { echo "\nencountered installation issues!"; $bFoundIssues = true; } else { try { - $oMysqli = CMDBSource::GetMysqliInstance($sDBServer, $sDBUser, $sDBPwd, null, $bDBTlsEnabled, $sDBTlsCa, true); - if ($oMysqli->select_db($sDBName)) { - // Check the presence of a table to record information about the MTP (from the Designer) - $sDesignerUpdatesTable = $sDBPrefix.'priv_designer_update'; - $sSQL = "SELECT id FROM `$sDesignerUpdatesTable`"; - if ($oMysqli->query($sSQL) !== false) { - // Record the Designer Udpates in the priv_designer_update table - $sDeltaFile = APPROOT.'data/'.$sTargetEnvironment.'.delta.xml'; - if (is_readable($sDeltaFile)) { + $sDeltaFile = APPROOT.'data/'.$sTargetEnvironment.'.delta.xml'; + if (is_readable($sDeltaFile)) { + $oMysqli = CMDBSource::GetMysqliInstance($sDBServer, $sDBUser, $sDBPwd, null, $bDBTlsEnabled, $sDBTlsCa, true); + if ($oMysqli->select_db($sDBName)) { + // Check the presence of a table to record information about the MTP (from the Designer) + $sDesignerUpdatesTable = $sDBPrefix.'priv_designer_update'; + $sSQL = "SELECT id FROM `$sDesignerUpdatesTable`"; + if ($oMysqli->query($sSQL) !== false) { + // Record the Designer Udpates in the priv_designer_update table // Retrieve the revision $oDoc = new DOMDocument(); $oDoc->load($sDeltaFile); @@ -301,12 +312,7 @@ if ($bInstall) { } else { echo "\nFailed to record designer updates(".$oMysqli->error.").\n"; } - } else { - echo "\nFailed to read the revision from $sDeltaFile file. No designer update information will be recorded.\n"; - } - } else { - echo "\nNo $sDeltaFile file (or the file is not accessible). No designer update information to record.\n"; } } } @@ -340,8 +346,7 @@ if (! $bFoundIssues) { $sLogMsg = "installed!"; if ($bUseItopConfig && is_file("$sConfigFile.backup")) { - echo "\nuse config file provided by backup in $sConfigFile."; - copy("$sConfigFile.backup", $sConfigFile); + unlink("$sConfigFile.backup"); } SetupLog::Info($sLogMsg); diff --git a/setup/unattended-install/xml_setup/fresh-install.xml b/setup/unattended-install/xml_setup/fresh-install.xml index db1311cf55..f44b7cdb80 100644 --- a/setup/unattended-install/xml_setup/fresh-install.xml +++ b/setup/unattended-install/xml_setup/fresh-install.xml @@ -1,11 +1,14 @@ install - - + + 1 + 1 + 1 + 1 + datamodels/2.x/ - 2.7.0 - /var/www/html/iTop/conf/production/config-itop.php + 3.3.0 extensions production @@ -38,4 +41,5 @@ + off diff --git a/setup/unattended-install/xml_setup/itil-fresh-install.xml b/setup/unattended-install/xml_setup/itil-fresh-install.xml index e1b1e594f0..f1979e20b4 100644 --- a/setup/unattended-install/xml_setup/itil-fresh-install.xml +++ b/setup/unattended-install/xml_setup/itil-fresh-install.xml @@ -1,11 +1,14 @@ install - - + + 1 + 1 + 1 + 1 + datamodels/2.x/ - 2.7.0 - /var/www/html/iTop/conf/production/config-itop.php + 3.3.0 extensions production @@ -50,4 +53,5 @@ itop-config-mgmt-core itop-kown-error-mgmt + off diff --git a/setup/unattended-install/xml_setup/itil-upgrade.xml b/setup/unattended-install/xml_setup/itil-upgrade.xml index eb0a63208a..8a8900b791 100644 --- a/setup/unattended-install/xml_setup/itil-upgrade.xml +++ b/setup/unattended-install/xml_setup/itil-upgrade.xml @@ -1,11 +1,14 @@ upgrade - - + + 1 + 1 + 1 + 1 + datamodels/2.x/ - 2.7.0 - /var/www/html/iTop/conf/production/config-itop.php + 3.3.0 extensions production @@ -50,4 +53,5 @@ itop-config-mgmt-core itop-kown-error-mgmt + off diff --git a/setup/unattended-install/xml_setup/upgrade.xml b/setup/unattended-install/xml_setup/upgrade.xml index ff0d153f1e..0272bd2551 100644 --- a/setup/unattended-install/xml_setup/upgrade.xml +++ b/setup/unattended-install/xml_setup/upgrade.xml @@ -1,11 +1,14 @@ upgrade - - + + 1 + 1 + 1 + 1 + datamodels/2.x/ - 2.7.0 - /var/www/html/iTop/conf/production/config-itop.php + 3.3.0 extensions production @@ -38,4 +41,5 @@ - \ No newline at end of file + off + diff --git a/setup/wizard.php b/setup/wizard.php index 5d52ec952e..f48fda0c29 100644 --- a/setup/wizard.php +++ b/setup/wizard.php @@ -31,8 +31,7 @@ require_once('../approot.inc.php'); require_once(APPROOT.'/application/utils.inc.php'); require_once(APPROOT.'/core/config.class.inc.php'); require_once(APPROOT.'/setup/setuppage.class.inc.php'); -require_once(APPROOT.'/setup/wizardcontroller.class.inc.php'); -require_once(APPROOT.'/setup/wizardsteps.class.inc.php'); +require_once(APPROOT.'/setup/wizardsteps_autoload.php'); Session::Start(); clearstatcache(); // Make sure we know what we are doing ! diff --git a/setup/wizardcontroller.class.inc.php b/setup/wizardcontroller.class.inc.php index 589c5c8a38..eace6760da 100644 --- a/setup/wizardcontroller.class.inc.php +++ b/setup/wizardcontroller.class.inc.php @@ -16,8 +16,12 @@ // // You should have received a copy of the GNU Affero General Public License // along with iTop. If not, see -use Combodo\iTop\Application\UI\Base\Component\Html\Html; -use Combodo\iTop\Application\WebPage\WebPage; + +require_once(APPROOT.'setup/setuputils.class.inc.php'); +require_once(APPROOT.'setup/parameters.class.inc.php'); +require_once(APPROOT.'setup/applicationinstaller.class.inc.php'); +require_once(APPROOT.'core/mutex.class.inc.php'); +require_once(APPROOT.'setup/extensionsmap.class.inc.php'); /** * Engine for displaying the various pages of a "wizard" @@ -34,7 +38,7 @@ use Combodo\iTop\Application\WebPage\WebPage; class WizardController { - protected $aSteps; + protected $aWizardSteps; protected $sInitialStepClass; protected $sInitialState; protected $aParameters; @@ -49,25 +53,25 @@ class WizardController $this->sInitialStepClass = $sInitialStepClass; $this->sInitialState = $sInitialState; $this->aParameters = []; - $this->aSteps = []; + $this->aWizardSteps = []; } /** * Pushes information about the current step onto the stack - * @param hash $aStepInfo Array('class' => , 'state' => ) + * @param array $aStepInfo Array('class' => , 'state' => ) */ protected function PushStep($aStepInfo) { - array_push($this->aSteps, $aStepInfo); + array_push($this->aWizardSteps, $aStepInfo); } /** * Removes information about the previous step from the stack - * @return hash Array('class' => , 'state' => ) + * @return array{'class': string, 'state': string} */ protected function PopStep() { - return array_pop($this->aSteps); + return array_pop($this->aWizardSteps); } /** @@ -134,7 +138,7 @@ class WizardController public function Start() { $sCurrentStepClass = $this->sInitialStepClass; - $oStep = new $sCurrentStepClass($this, $this->sInitialState); + $oStep = $this->GetWizardStep($sCurrentStepClass, $this->sInitialState); $this->DisplayStep($oStep); } /** @@ -145,22 +149,24 @@ class WizardController { $sCurrentStepClass = utils::ReadParam('_class', $this->sInitialStepClass); $sCurrentState = utils::ReadParam('_state', $this->sInitialState); - /** @var \WizardStep $oStep */ - $oStep = new $sCurrentStepClass($this, $sCurrentState); + $oStep = $this->GetWizardStep($sCurrentStepClass, $sCurrentState); if ($oStep->ValidateParams()) { - $this->PushStep(['class' => $sCurrentStepClass, 'state' => $sCurrentState]); + if ($oStep->CanComeBack()) { + $this->PushStep(['class' => $sCurrentStepClass, 'state' => $sCurrentState]); + } $aPossibleSteps = $oStep->GetPossibleSteps(); - $aNextStepInfo = $oStep->ProcessParams(true); // true => moving forward - if (in_array($aNextStepInfo['class'], $aPossibleSteps)) { - $oNextStep = new $aNextStepInfo['class']($this, $aNextStepInfo['state']); + $oWizardState = $oStep->UpdateWizardStateAndGetNextStep(true); // true => moving forward + if (in_array($oWizardState->GetNextStep(), $aPossibleSteps)) { + $oNextStep = $this->GetWizardStep($oWizardState->GetNextStep(), $oWizardState->GetState()); $this->DisplayStep($oNextStep); } else { - throw new Exception("Internal error: Unexpected next step '{$aNextStepInfo['class']}'. The possible next steps are: ".implode(', ', $aPossibleSteps)); + throw new Exception("Internal error: Unexpected next step '{$oWizardState->GetNextStep()}'. The possible next steps are: ".implode(', ', $aPossibleSteps)); } } else { $this->DisplayStep($oStep); } } + /** * Move one step back */ @@ -169,30 +175,34 @@ class WizardController // let the current step save its parameters $sCurrentStepClass = utils::ReadParam('_class', $this->sInitialStepClass); $sCurrentState = utils::ReadParam('_state', $this->sInitialState); - $oStep = new $sCurrentStepClass($this, $sCurrentState); - $aNextStepInfo = $oStep->ProcessParams(false); // false => Moving backwards + $oStep = $this->GetWizardStep($sCurrentStepClass, $sCurrentState); + $oStep->UpdateWizardStateAndGetNextStep(false); // false => Moving backwards // Display the previous step $aCurrentStepInfo = $this->PopStep(); - $oStep = new $aCurrentStepInfo['class']($this, $aCurrentStepInfo['state']); + $oStep = $this->GetWizardStep($aCurrentStepInfo['class'], $aCurrentStepInfo['state']); $this->DisplayStep($oStep); } /** * Displays the specified 'step' of the wizard + * * @param WizardStep $oStep The 'step' to display + * + * @throws \Exception */ - protected function DisplayStep(WizardStep $oStep) + protected function DisplayStep(WizardStep $oStep): void { + SetupLog::Info("=== Setup screen: ".$oStep->GetTitle().' ('.get_class($oStep).')'); $oPage = new SetupPage($oStep->GetTitle()); if ($oStep->RequiresWritableConfig()) { - $sConfigFile = utils::GetConfigFilePath(); + $sConfigFile = utils::GetConfigFilePath(ITOP_DEFAULT_ENV); if (file_exists($sConfigFile)) { // The configuration file already exists if (!is_writable($sConfigFile)) { SetupUtils::ExitReadOnlyMode(false); // Reset readonly mode in case of problem SetupUtils::EraseSetupToken(); - $sRelativePath = utils::GetConfigFilePathRelative(); + $sRelativePath = utils::GetConfigFilePathRelative(ITOP_DEFAULT_ENV); $oP = new SetupPage('Installation Cannot Continue'); $oP->add("

Fatal error

\n"); $oP->error("Error: the configuration file '".$sRelativePath."' already exists and cannot be overwritten."); @@ -225,9 +235,9 @@ HTML; $oPage->add(''); } - $oPage->add(''); + $oPage->add(''); $oPage->add(''); - if ((count($this->aSteps) > 0) && ($oStep->CanMoveBackward())) { + if ((count($this->aWizardSteps) > 0) && ($oStep->CanMoveBackward())) { $oPage->add(''); } if ($oStep->CanMoveForward()) { @@ -235,6 +245,7 @@ HTML; } $oPage->add('
'); $oPage->add(""); + $oStep->PostFormDisplay($oPage); $oPage->add(''); // The div may become visible in case of error // Hack to have the "Next >>" button, be the default button, since the first submit button in the form is the default one @@ -285,7 +296,7 @@ on the page's parameters $sOperation = utils::ReadParam('operation'); $this->aParameters = utils::ReadParam('_params', [], false, 'raw_data'); - $this->aSteps = json_decode(utils::ReadParam('_steps', '[]', false, 'raw_data'), true /* bAssoc */); + $this->SetWizardSteps(json_decode(utils::ReadParam('_steps', '[]', false, 'raw_data'), true)); switch ($sOperation) { case 'next': @@ -305,7 +316,7 @@ on the page's parameters * Provides information about the structure/workflow of the wizard by listing * the possible list of 'steps' and their dependencies * @param string $sStep Name of the class to start from (used for recursion) - * @param hash $aAllSteps List of steps (used for recursion) + * @param array $aAllSteps List of steps (used for recursion) */ public function DumpStructure($sStep = '', $aAllSteps = null) { @@ -316,7 +327,7 @@ on the page's parameters $sStep = $this->sInitialStepClass; } - $oStep = new $sStep($this, ''); + $oStep = $this->GetWizardStep($sStep); $aAllSteps[$sStep] = $oStep->GetPossibleSteps(); foreach ($aAllSteps[$sStep] as $sNextStep) { if (!array_key_exists($sNextStep, $aAllSteps)) { @@ -348,7 +359,7 @@ on the page's parameters $sOutput .= "\tnode [shape = doublecircle]; ".implode(' ', $aDeadEnds).";\n"; $sOutput .= "\tnode [shape = box];\n"; foreach ($aAllSteps as $sStep => $aNextSteps) { - $oStep = new $sStep($this, ''); + $oStep = $this->GetWizardStep($sStep); $sOutput .= "\t$sStep [ label = \"".$oStep->GetTitle()."\"];\n"; if (count($aNextSteps) > 0) { foreach ($aNextSteps as $sNextStep) { @@ -359,326 +370,24 @@ on the page's parameters $sOutput .= "}\n"; return $sOutput; } -} -/** - * Abstract class to build "steps" for the wizard controller - * If a step needs to maintain an internal "state" (for complex steps) - * then it's up to the derived class to implement the behavior based on - * the internal 'sCurrentState' variable. - * @copyright Copyright (C) 2010-2024 Combodo SAS - * @license http://opensource.org/licenses/AGPL-3.0 - */ - -abstract class WizardStep -{ - /** - * A reference to the WizardController - * @var WizardController - */ - protected $oWizard; - /** - * Current 'state' of the wizard step. Simple 'steps' can ignore it - * @var string - */ - protected $sCurrentState; - - public function __construct(WizardController $oWizard, $sCurrentState) + public function SetWizardSteps(array $aWizardSteps): void { - $this->oWizard = $oWizard; - $this->sCurrentState = $sCurrentState; - } - - public function GetState() - { - return $this->sCurrentState; + $this->aWizardSteps = $aWizardSteps; } /** - * Displays the wizard page for the current class/state - * The page can contain any number of "" fields, but no "
...
" tag - * The name of the input fields (and their id if one is supplied) MUST NOT start with "_" - * (this is reserved for the wizard's own parameters) - * @return void + * @param string $sCurrentStepClass + * @param string $sCurrentState + * + * @return \WizardStep + * @throws \Exception */ - abstract public function Display(WebPage $oPage); - /** - * Displays the wizard page for the current class/state - * return UIBlock - * The name of the input fields (and their id if one is supplied) MUST NOT start with "_" - * (this is reserved for the wizard's own parameters) - * @return \Combodo\iTop\Application\UI\Base\UIBlock - * @since 3.0.0 - */ - public function DisplayBlock(WebPage $oPage) + private function GetWizardStep(string $sCurrentStepClass, string $sCurrentState = ''): WizardStep { - return new Html($this->Display($oPage)); - } - - /** - * Processes the page's parameters and (if moving forward) returns the next step/state to be displayed - * @param bool $bMoveForward True if the wizard is moving forward 'Next >>' button pressed, false otherwise - * @return hash array('class' => $sNextClass, 'state' => $sNextState) - */ - abstract public function ProcessParams($bMoveForward = true); - - /** - * Returns the list of possible steps from this step forward - * @return array Array of strings (step classes) - */ - abstract public function GetPossibleSteps(); - - /** - * Returns title of the current step - * @return string The title of the wizard page for the current step - */ - abstract public function GetTitle(); - - /** - * Tells whether the parameters are Ok to move forward - * @return boolean True to move forward, false to stey on the same step - */ - public function ValidateParams() - { - return true; - } - - /** - * Tells whether this step/state is the last one of the wizard (dead-end) - * @return boolean True if the 'Next >>' button should be displayed - */ - public function CanMoveForward() - { - return true; - } - - /** - * Tells whether the "Next" button should be enabled interactively - * @return string A piece of javascript code returning either true or false - */ - public function JSCanMoveForward() - { - return 'return true;'; - } - - /** - * Returns the label for the " Next >> " button - * @return string The label for the button - */ - public function GetNextButtonLabel() - { - return 'Next'; - } - - /** - * Tells whether this step/state allows to go back or not - * @return boolean True if the '<< Back' button should be displayed - */ - public function CanMoveBackward() - { - return true; - } - - /** - * Tells whether the "Back" button should be enabled interactively - * @return string A piece of javascript code returning either true or false - */ - public function JSCanMoveBackward() - { - return 'return true;'; - } - - /** - * Tells whether this step of the wizard requires that the configuration file be writable - * @return bool True if the wizard will possibly need to modify the configuration at some point - */ - public function RequiresWritableConfig() - { - return true; - } - - /** - * Overload this function to implement asynchronous action(s) (AJAX) - * @param string $sCode The code of the action (if several actions need to be distinguished) - * @param hash $aParameters The action's parameters name => value - */ - public function AsyncAction(WebPage $oPage, $sCode, $aParameters) - { - } -} - -/* - * Example of a simple Setup Wizard with some parameters to store - * the installation mode (install | upgrade) and a simple asynchronous - * (AJAX) action. - * - * The setup wizard is executed by the following code: - * - * $oWizard = new WizardController('Step1'); - * $oWizard->Run(); - * -class Step1 extends WizardStep -{ - public function GetTitle() - { - return 'Welcome'; - } - - public function GetPossibleSteps() - { - return array('Step2', 'Step2bis'); - } - - public function ProcessParams($bMoveForward = true) - { - $sNextStep = ''; - $sInstallMode = utils::ReadParam('install_mode'); - if ($sInstallMode == 'install') - { - $this->oWizard->SetParameter('install_mode', 'install'); - $sNextStep = 'Step2'; + if (!is_subclass_of($sCurrentStepClass, WizardStep::class)) { + throw new Exception('Unknown step '.$sCurrentStepClass); } - else - { - $this->oWizard->SetParameter('install_mode', 'upgrade'); - $sNextStep = 'Step2bis'; - - } - return array('class' => $sNextStep, 'state' => ''); - } - - public function Display(WebPage $oPage) - { - $oPage->p('This is Step 1!'); - $sInstallMode = $this->oWizard->GetParameter('install_mode', 'install'); - $sChecked = ($sInstallMode == 'install') ? ' checked ' : ''; - $oPage->p(' Install'); - $sChecked = ($sInstallMode == 'upgrade') ? ' checked ' : ''; - $oPage->p(' Upgrade'); + return new $sCurrentStepClass($this, $sCurrentState); } } - -class Step2 extends WizardStep -{ - public function GetTitle() - { - return 'Installation Parameters'; - } - - public function GetPossibleSteps() - { - return array('Step3'); - } - - public function ProcessParams($bMoveForward = true) - { - return array('class' => 'Step3', 'state' => ''); - } - - public function Display(WebPage $oPage) - { - $oPage->p('This is Step 2! (Installation)'); - } -} - -class Step2bis extends WizardStep -{ - public function GetTitle() - { - return 'Upgrade Parameters'; - } - - public function GetPossibleSteps() - { - return array('Step2ter'); - } - - public function ProcessParams($bMoveForward = true) - { - $sUpgradeInfo = utils::ReadParam('upgrade_info'); - $this->oWizard->SetParameter('upgrade_info', $sUpgradeInfo); - $sAdditionalUpgradeInfo = utils::ReadParam('additional_upgrade_info'); - $this->oWizard->SetParameter('additional_upgrade_info', $sAdditionalUpgradeInfo); - return array('class' => 'Step2ter', 'state' => ''); - } - - public function Display(WebPage $oPage) - { - $oPage->p('This is Step 2bis! (Upgrade)'); - $sUpgradeInfo = $this->oWizard->GetParameter('upgrade_info', ''); - $oPage->p('Type your name here: '); - $sAdditionalUpgradeInfo = $this->oWizard->GetParameter('additional_upgrade_info', ''); - $oPage->p('The installer replies: '); - - $oPage->add_ready_script("$('#upgrade_info').change(function() { - $('#v_upgrade_info').html(''); - WizardAsyncAction('', { upgrade_info: $('#upgrade_info').val() }); });"); - } - - public function AsyncAction(WebPage $oPage, $sCode, $aParameters) - { - usleep(300000); // 300 ms - $sName = $aParameters['upgrade_info']; - $sReply = addslashes("Hello ".$sName); - - $oPage->add_ready_script( -<< 'Step3', 'state' => ''); - } - - public function Display(WebPage $oPage) - { - $oPage->p('This is Step 2ter! (Upgrade)'); - } -} - -class Step3 extends WizardStep -{ - public function GetTitle() - { - return 'Installation Complete'; - } - - public function GetPossibleSteps() - { - return array(); - } - - public function ProcessParams($bMoveForward = true) - { - return array('class' => '', 'state' => ''); - } - - public function Display(WebPage $oPage) - { - $oPage->p('This is the FINAL Step'); - } - - public function CanMoveForward() - { - return false; - } -} - -End of the example */ diff --git a/setup/wizardsteps.class.inc.php b/setup/wizardsteps.class.inc.php deleted file mode 100644 index 510f84777b..0000000000 --- a/setup/wizardsteps.class.inc.php +++ /dev/null @@ -1,2584 +0,0 @@ - - * WizStepLicense WizStepDetectedInfo - * WizStepDBParams + + - * WizStepAdminAccount | | - * WizStepInstallMiscParams v +------> - * + WizStepLicense2 +--> WizStepUpgradeMiscParams - * | + - * +---> <-----------------------------------+ - * WizStepModulesChoice - * WizStepSummary - * WizStepDone - */ - -use Combodo\iTop\Application\WebPage\WebPage; -use Combodo\iTop\PhpParser\Evaluation\PhpExpressionEvaluator; -use Combodo\iTop\Setup\ModuleDiscovery\ModuleFileReaderException; - -require_once(APPROOT.'setup/setuputils.class.inc.php'); -require_once(APPROOT.'setup/parameters.class.inc.php'); -require_once(APPROOT.'setup/applicationinstaller.class.inc.php'); -require_once(APPROOT.'setup/parameters.class.inc.php'); -require_once(APPROOT.'core/mutex.class.inc.php'); -require_once(APPROOT.'setup/extensionsmap.class.inc.php'); - -/** - * First step of the iTop Installation Wizard: Welcome screen, requirements - */ -class WizStepWelcome extends WizardStep -{ - protected $bCanMoveForward; - - public function GetTitle() - { - return 'Welcome to '.ITOP_APPLICATION.' version '.ITOP_VERSION; - } - - /** - * Returns the label for the " Next >> " button - * @return string The label for the button - */ - public function GetNextButtonLabel() - { - return 'Continue'; - } - - public function GetPossibleSteps() - { - return ['WizStepInstallOrUpgrade']; - } - - public function ProcessParams($bMoveForward = true) - { - $sUID = SetupUtils::CreateSetupToken(); - $this->oWizard->SetParameter('authent', $sUID); - return ['class' => 'WizStepInstallOrUpgrade', 'state' => '']; - } - - public function Display(WebPage $oPage) - { - // Store the misc_options for the future... - $aMiscOptions = utils::ReadParam('option', [], false, 'raw_data'); - $sMiscOptions = $this->oWizard->GetParameter('misc_options', json_encode($aMiscOptions)); - $this->oWizard->SetParameter('misc_options', $sMiscOptions); - - $oPage->add(""); - $oPage->add_ready_script( - << 0) - { - alert("Internet Explorer version 10 or older is NOT supported! (Check that IE is not running in compatibility mode)"); - } -EOF - ); - $oPage->add('

'.ITOP_APPLICATION.' Installation Wizard

'); - $aResults = SetupUtils::CheckPhpAndExtensions(); - $this->bCanMoveForward = true; - $aInfo = []; - $aWarnings = []; - $aErrors = []; - foreach ($aResults as $oCheckResult) { - switch ($oCheckResult->iSeverity) { - case CheckResult::ERROR: - $aErrors[] = $oCheckResult->sLabel; - $this->bCanMoveForward = false; - break; - - case CheckResult::WARNING: - $aWarnings[] = $oCheckResult->sLabel; - break; - - case CheckResult::INFO: - $aInfo[] = $oCheckResult->sLabel; - break; - - case CheckResult::TRACE: - SetupLog::Ok($oCheckResult->sLabel); - break; - } - } - $sStyle = 'style="display:none;overflow:auto;"'; - $sToggleButtons = ''; - if (count($aErrors) > 0) { - $sStyle = 'overflow:auto;"'; - $sTitle = count($aErrors).' Error(s), '.count($aWarnings).' Warning(s).'; - $sH2Class = 'text-error'; - } elseif (count($aWarnings) > 0) { - $sTitle = count($aWarnings).' Warning(s) '.$sToggleButtons; - $sH2Class = 'text-warning'; - } else { - $sTitle = 'Ok. '.$sToggleButtons; - $sH2Class = 'text-valid'; - } - $oPage->add( - <<Prerequisites validation: $sTitle -
-HTML - ); - foreach ($aErrors as $sText) { - $oPage->error($sText); - } - foreach ($aWarnings as $sText) { - $oPage->warning($sText); - } - foreach ($aInfo as $sText) { - $oPage->ok($sText); - } - $oPage->add('
'); - if (!$this->bCanMoveForward) { - $oPage->p('Sorry, the installation cannot continue. Please fix the errors and reload this page to launch the installation again.'); - $oPage->p(''); - } - $oPage->add_ready_script('CheckDirectoryConfFilesPermissions("'.utils::GetItopVersionWikiSyntax().'")'); - } - - public function CanMoveForward() - { - return $this->bCanMoveForward; - } -} - -/** - * Second step of the iTop Installation Wizard: Install or Upgrade - */ -class WizStepInstallOrUpgrade extends WizardStep -{ - public function GetTitle() - { - return 'Install or Upgrade choice'; - } - - public function GetPossibleSteps() - { - return ['WizStepDetectedInfo', 'WizStepLicense']; - } - - public function ProcessParams($bMoveForward = true) - { - $sNextStep = ''; - $sInstallMode = utils::ReadParam('install_mode'); - - $this->oWizard->SaveParameter('previous_version_dir', ''); - $this->oWizard->SaveParameter('db_server', ''); - $this->oWizard->SaveParameter('db_user', ''); - $this->oWizard->SaveParameter('db_pwd', ''); - $this->oWizard->SaveParameter('db_name', ''); - $this->oWizard->SaveParameter('db_prefix', ''); - $this->oWizard->SaveParameter('db_backup', false); - $this->oWizard->SaveParameter('db_backup_path', ''); - $this->oWizard->SaveParameter('db_tls_enabled', false); - $this->oWizard->SaveParameter('db_tls_ca', ''); - - if ($sInstallMode == 'install') { - $this->oWizard->SetParameter('install_mode', 'install'); - $sFullSourceDir = SetupUtils::GetLatestDataModelDir(); - $this->oWizard->SetParameter('source_dir', $sFullSourceDir); - $this->oWizard->SetParameter('datamodel_version', SetupUtils::GetDataModelVersion($sFullSourceDir)); - $sNextStep = 'WizStepLicense'; - } else { - $this->oWizard->SetParameter('install_mode', 'upgrade'); - $sNextStep = 'WizStepDetectedInfo'; - - } - return ['class' => $sNextStep, 'state' => '']; - } - - public function Display(WebPage $oPage) - { - $sInstallMode = $this->oWizard->GetParameter('install_mode', ''); - $sDBServer = $this->oWizard->GetParameter('db_server', ''); - $sDBUser = $this->oWizard->GetParameter('db_user', ''); - $sDBPwd = $this->oWizard->GetParameter('db_pwd', ''); - $sDBName = $this->oWizard->GetParameter('db_name', ''); - $sDBPrefix = $this->oWizard->GetParameter('db_prefix', ''); - $bDBBackup = $this->oWizard->GetParameter('db_backup', false); - $sDBBackupPath = $this->oWizard->GetParameter('db_backup_path', ''); - $sTlsEnabled = $this->oWizard->GetParameter('db_tls_enabled', false); - $sTlsCA = $this->oWizard->GetParameter('db_tls_ca', ''); - $sMySQLBinDir = $this->oWizard->GetParameter('mysql_bindir', null); - $sPreviousVersionDir = ''; - if ($sInstallMode == '') { - $sDBBackupPath = utils::GetDataPath().'backups/manual/setup-'.date('Y-m-d_H_i'); - $bDBBackup = true; - $aPreviousInstance = SetupUtils::GetPreviousInstance(APPROOT); - if ($aPreviousInstance['found']) { - $sInstallMode = 'upgrade'; - $sDBServer = $aPreviousInstance['db_server']; - $sDBUser = $aPreviousInstance['db_user']; - $sDBPwd = $aPreviousInstance['db_pwd']; - $sDBName = $aPreviousInstance['db_name']; - $sDBPrefix = $aPreviousInstance['db_prefix']; - $sTlsEnabled = $aPreviousInstance['db_tls_enabled']; - $sTlsCA = $aPreviousInstance['db_tls_ca']; - $this->oWizard->SaveParameter('graphviz_path', $aPreviousInstance['graphviz_path']); - $sMySQLBinDir = $aPreviousInstance['mysql_bindir']; - $this->oWizard->SaveParameter('mysql_bindir', $aPreviousInstance['mysql_bindir']); - $sPreviousVersionDir = APPROOT; - } else { - $sInstallMode = 'install'; - } - } - $sPreviousVersionDir = $this->oWizard->GetParameter('previous_version_dir', $sPreviousVersionDir); - - $sUpgradeInfoStyle = ''; - if ($sInstallMode == 'install') { - $sUpgradeInfoStyle = ' style="display: none;" '; - } - $oPage->add('
What do you want to do?
'); - $sChecked = ($sInstallMode == 'install') ? ' checked ' : ''; - $oPage->p(''); - $sChecked = ($sInstallMode == 'upgrade') ? ' checked ' : ''; - $sDisabled = (($sInstallMode == 'install') && (empty($sPreviousVersionDir))) ? ' disabled' : ''; - $oPage->p(''); - - $sUpgradeDir = utils::HtmlEntities($sPreviousVersionDir); - $oPage->add( - << -
Location on the disk: -
-HTML - ); - - SetupUtils::DisplayDBParameters( - $oPage, - false, - $sDBServer, - $sDBUser, - $sDBPwd, - $sDBName, - $sDBPrefix, - $sTlsEnabled, - $sTlsCA, - null - ); - - $aBackupChecks = SetupUtils::CheckBackupPrerequisites($sDBBackupPath, $sMySQLBinDir); - $bCanBackup = true; - $sMySQLDumpMessage = ''; - foreach ($aBackupChecks as $oCheck) { - switch ($oCheck->iSeverity) { - case CheckResult::ERROR: - $bCanBackup = false; - $sMySQLDumpMessage .= '
Error:'.$oCheck->sLabel.'
'; - break; - case CheckResult::TRACE: - SetupLog::Ok($oCheck->sLabel); - break; - default: - $sMySQLDumpMessage .= '
Success:'.$oCheck->sLabel.'
'; - break; - } - } - $sChecked = ($bCanBackup && $bDBBackup) ? ' checked ' : ''; - $sDisabled = $bCanBackup ? '' : ' disabled '; - $oPage->add(''); - $oPage->add('
Save the backup to:
'); - $fFreeSpace = SetupUtils::CheckDiskSpace($sDBBackupPath); - $sMessage = ''; - if ($fFreeSpace !== false) { - $sMessage .= SetupUtils::HumanReadableSize($fFreeSpace).' free in '.dirname($sDBBackupPath); - } - $oPage->add($sMySQLDumpMessage.''.$sMessage.''); - $oPage->add(''); - $sAuthentToken = $this->oWizard->GetParameter('authent', ''); - $oPage->add(''); - //$oPage->add(''); - $oPage->add_ready_script( - <<add_ready_script( - <<add_ready_script( - <<add_ready_script( - <<oWizard->SetParameter('mode', 'upgrade'); - $this->oWizard->SetParameter('upgrade_type', $sUpgradeType); - $bDisplayLicense = $this->oWizard->GetParameter('display_license'); - - switch ($sUpgradeType) { - case 'keep-previous': - $sSourceDir = utils::ReadParam('relative_source_dir', '', false, 'raw_data'); - $this->oWizard->SetParameter('source_dir', $this->oWizard->GetParameter('previous_version_dir').'/'.$sSourceDir); - $this->oWizard->SetParameter('datamodel_version', utils::ReadParam('datamodel_previous_version', '', false, 'raw_data')); - break; - - case 'use-compatible': - $sDataModelPath = utils::ReadParam('datamodel_path', '', false, 'raw_data'); - $this->oWizard->SetParameter('source_dir', $sDataModelPath); - $this->oWizard->SaveParameter('datamodel_version', ''); - break; - - default: - // Do nothing, maybe the user pressed the Back button - } - if ($bDisplayLicense) { - $aRet = ['class' => 'WizStepLicense2', 'state' => '']; - } else { - $aRet = ['class' => 'WizStepUpgradeMiscParams', 'state' => '']; - } - return $aRet; - } - - /** - * @param WebPage $oPage - * - * @throws Exception - */ - public function Display(WebPage $oPage) - { - $oPage->add_style( - <<bCanMoveForward = true; - $bDisplayLicense = true; - $sPreviousVersionDir = $this->oWizard->GetParameter('previous_version_dir', ''); - $aInstalledInfo = SetupUtils::GetApplicationVersion($this->oWizard); - - if ($aInstalledInfo === false) { - throw(new Exception('No previous version of '.ITOP_APPLICATION.' found in the supplied database. The upgrade cannot continue.')); - } elseif (strcasecmp($aInstalledInfo['product_name'], ITOP_APPLICATION) != 0) { - $oPage->p("Warning: The installed products seem different. Are you sure that you want to upgrade {$aInstalledInfo['product_name']} with ".ITOP_APPLICATION."?"); - } - - $sInstalledVersion = $aInstalledInfo['product_version']; - $sInstalledDataModelVersion = $aInstalledInfo['datamodel_version']; - - $oPage->add("

Information about the upgrade from version $sInstalledVersion to ".ITOP_VERSION_FULL."

"); - - if ($sInstalledVersion == ITOP_VERSION_FULL) { - // Reinstalling the same version let's skip the license agreement... - $bDisplayLicense = false; - } - $this->oWizard->SetParameter('license', $bDisplayLicense); // Remember for later - - $sCompatibleDMDir = SetupUtils::GetLatestDataModelDir(); - if ($sCompatibleDMDir === false) { - // No compatible version exists... cannot upgrade. Either it is too old, or too new (downgrade !) - $this->bCanMoveForward = false; - $oPage->p("No datamodel directory found."); - } else { - $sUpgradeDMVersion = SetupUtils::GetDataModelVersion($sCompatibleDMDir); - $sPreviousSourceDir = isset($aInstalledInfo['source_dir']) ? $aInstalledInfo['source_dir'] : 'modules'; - $aChanges = false; - if (is_dir($sPreviousVersionDir)) { - // Check if the previous version is a "genuine" one or not... - $aChanges = SetupUtils::CheckVersion($sInstalledDataModelVersion, $sPreviousVersionDir.'/'.$sPreviousSourceDir); - } - if (($aChanges !== false) && ((count($aChanges['added']) > 0) || (count($aChanges['removed']) > 0) || (count($aChanges['modified']) > 0))) { - // Some changes were detected, prompt the user to keep or discard them - $oPage->p(" Some modifications were detected between the ".ITOP_APPLICATION." version in '$sPreviousVersionDir' and a genuine $sInstalledVersion version."); - $oPage->p("What do you want to do?"); - - $aWritableDirs = ['modules', 'portal']; - $aErrors = SetupUtils::CheckWritableDirs($aWritableDirs); - $sChecked = ($this->oWizard->GetParameter('upgrade_type') == 'keep-previous') ? ' checked ' : ''; - $sDisabled = (count($aErrors) > 0) ? ' disabled ' : ''; - - $oPage->p(''); - $oPage->add(''); - - $oPage->add(''); - - if (count($aErrors) > 0) { - $oPage->p("Cannot copy the installed version due to the following access rights issue(s):"); - foreach ($aErrors as $sDir => $oCheckResult) { - $oPage->p(' '.$oCheckResult->sLabel); - } - } - - $sChecked = ($this->oWizard->GetParameter('upgrade_type') == 'use-compatible') ? ' checked ' : ''; - - $oPage->p(''); - - $oPage->add(''); - $oPage->add(''); - - $oPage->add('
Details of the modifications
'); - if (count($aChanges['added']) > 0) { - $oPage->add('
    New files added:'); - foreach ($aChanges['added'] as $sFilePath => $void) { - $oPage->add('
  • '.$sFilePath.'
  • '); - } - $oPage->add('
'); - } - if (count($aChanges['removed']) > 0) { - $oPage->add('
    Deleted files:'); - foreach ($aChanges['removed'] as $sFilePath => $void) { - $oPage->add('
  • '.$sFilePath.'
  • '); - } - $oPage->add('
'); - } - if (count($aChanges['modified']) > 0) { - $oPage->add('
    Modified files:'); - foreach ($aChanges['modified'] as $sFilePath => $void) { - $oPage->add('
  • '.$sFilePath.'
  • '); - } - $oPage->add('
'); - } - $oPage->add('
'); - } else { - // No changes detected... or no way to tell because of the lack of a manifest or previous source dir - // Use the "compatible" datamodel as-is. - $sCompatibleDMDirToDisplay = utils::HtmlEntities($sCompatibleDMDir); - $sUpgradeDMVersionToDisplay = utils::HtmlEntities($sUpgradeDMVersion); - $oPage->add( - <<The datamodel will be upgraded from version $sInstalledDataModelVersion to version $sUpgradeDMVersion. - - - -HTML - ); - - } - - $oPage->add_ready_script( - <<oWizard->GetParameter('db_name', '').$this->oWizard->GetParameter('db_prefix', ''), - $this->oWizard->GetParameter('db_server', ''), - $this->oWizard->GetParameter('db_user', ''), - $this->oWizard->GetParameter('db_pwd', ''), - $this->oWizard->GetParameter('db_tls_enabled', ''), - $this->oWizard->GetParameter('db_tls_ca', '') - ); - if ($oMutex->IsLocked()) { - $oPage->add('
'.ITOP_APPLICATION.' cron process is being executed on the target database. '.ITOP_APPLICATION.' cron process will be stopped during the setup execution.
'); - } - } - } - - public function CanMoveForward() - { - return $this->bCanMoveForward; - } - - /** - * Tells whether the "Next" button should be enabled interactively - * @return string A piece of javascript code returning either true or false - */ - public function JSCanMoveForward() - { - return - << 0); - return bRet; -EOF - ; - } -} - -/** - * License acceptation screen - */ -class WizStepLicense extends WizardStep -{ - public function GetTitle() - { - return 'License Agreement'; - } - - public function GetPossibleSteps() - { - return ['WizStepDBParams']; - } - - public function ProcessParams($bMoveForward = true) - { - $this->oWizard->SaveParameter('accept_license', 'no'); - return ['class' => 'WizStepDBParams', 'state' => '']; - } - - /** - * @return bool true if we need to display a GDPR confirmation - * @throws \Exception - * @since 2.7.7 3.0.2 3.1.0 N°5037 method creation - * @since 2.7.8 3.0.3 3.1.0 N°5758 rename from NeedsRgpdConsent to NeedsGdprConsent - */ - private function NeedsGdprConsent() - { - $sMode = $this->oWizard->GetParameter('install_mode'); - $aModules = SetupUtils::AnalyzeInstallation($this->oWizard); - - return (($sMode === 'install') && SetupUtils::IsConnectableToITopHub($aModules)); - } - - /** - * @param WebPage $oPage - */ - public function Display(WebPage $oPage) - { - $aLicenses = SetupUtils::GetLicenses(); - $oPage->add_style( - <<add('

Licenses agreements for the components of '.ITOP_APPLICATION.'

'); - $oPage->add_style('div a.no-arrow { background:transparent; padding-left:0;}'); - $oPage->add_style('.toggle { cursor:pointer; text-decoration:underline; color:#1C94C4; }'); - $oPage->add('
'); - $oPage->add('Components of '.ITOP_APPLICATION.''); - $oPage->add('
    '); - $index = 0; - foreach ($aLicenses as $oLicense) { - $oPage->add('
  • '.$oLicense->product.', © '.$oLicense->author.' is licensed under the '.$oLicense->license_type.' license. (Details)'); - $oPage->add(''); - $oPage->add_ready_script('$(".license_text a").attr("target", "_blank").addClass("no-arrow");'); - $oPage->add_ready_script('$("#toggle_'.$index.'").on("click", function() { $("#license_'.$index.'").toggle(); } );'); - $index++; - } - $oPage->add('
'); - $oPage->add('
'); - $sChecked = ($this->oWizard->GetParameter('accept_license', 'no') == 'yes') ? ' checked ' : ''; - $oPage->add('
'); - if ($this->NeedsGdprConsent()) { - $oPage->add('
'); - $oPage->add('
'); - $oPage->add('European General Data Protection Regulation'); - $oPage->add('
'.ITOP_APPLICATION.' software is compliant with the processing of personal data according to the European General Data Protection Regulation (GDPR).

-By installing '.ITOP_APPLICATION.' you agree that some information will be collected by Combodo to help you manage your instances and for statistical purposes. -This data remains anonymous until it is associated to a user account on iTop Hub.

-

List of collected data available in our Data privacy section.


'); - $oPage->add(''); - $oPage->add(''); - $oPage->add('
'); - } - $oPage->add_ready_script('$(".check_select").on("click change", function() { WizardUpdateButtons(); });'); - - $oPage->add_script( - << 'WizStepUpgradeMiscParams', 'state' => '']; - } -} - -/** - * Database Connection parameters screen - */ -class WizStepDBParams extends WizardStep -{ - public function GetTitle() - { - return 'Database Configuration'; - } - - public function GetPossibleSteps() - { - return ['WizStepAdminAccount']; - } - - public function ProcessParams($bMoveForward = true) - { - $this->oWizard->SaveParameter('db_server', ''); - $this->oWizard->SaveParameter('db_user', ''); - $this->oWizard->SaveParameter('db_pwd', ''); - $this->oWizard->SaveParameter('db_name', ''); - $this->oWizard->SaveParameter('db_prefix', ''); - $this->oWizard->SaveParameter('new_db_name', ''); - $this->oWizard->SaveParameter('create_db', ''); - $this->oWizard->SaveParameter('db_new_name', ''); - $this->oWizard->SaveParameter('db_tls_enabled', false); - $this->oWizard->SaveParameter('db_tls_ca', ''); - - return ['class' => 'WizStepAdminAccount', 'state' => '']; - } - - public function Display(WebPage $oPage) - { - $oPage->add('

Configuration of the database connection:

'); - $sDBServer = $this->oWizard->GetParameter('db_server', ''); - $sDBUser = $this->oWizard->GetParameter('db_user', ''); - $sDBPwd = $this->oWizard->GetParameter('db_pwd', ''); - $sDBName = $this->oWizard->GetParameter('db_name', ''); - $sDBPrefix = $this->oWizard->GetParameter('db_prefix', ''); - $sTlsEnabled = $this->oWizard->GetParameter('db_tls_enabled', ''); - $sTlsCA = $this->oWizard->GetParameter('db_tls_ca', ''); - $sNewDBName = $this->oWizard->GetParameter('db_new_name', false); - - $oPage->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') { - $oPage->add_ready_script('$("#existing_db").prop("checked", true);'); - } else { - $oPage->add_ready_script('$("#create_db").prop("checked", true);'); - } - } - - public function AsyncAction(WebPage $oPage, $sCode, $aParameters) - { - switch ($sCode) { - case 'check_db': - SetupUtils::AsyncCheckDB($oPage, $aParameters); - break; - } - } - - /** - * Tells whether the "Next" button should be enabled interactively - * @return string A piece of javascript code returning either true or false - */ - public function JSCanMoveForward() - { - return - <<oWizard->SaveParameter('admin_user', ''); - $this->oWizard->SaveParameter('admin_pwd', ''); - $this->oWizard->SaveParameter('confirm_pwd', ''); - $this->oWizard->SaveParameter('admin_language', 'EN US'); - - return ['class' => WizStepInstallMiscParams::class, 'state' => '']; - } - - public function Display(WebPage $oPage) - { - $sAdminUser = $this->oWizard->GetParameter('admin_user', 'admin'); - $sAdminPwd = $this->oWizard->GetParameter('admin_pwd', ''); - $sConfirmPwd = $this->oWizard->GetParameter('confirm_pwd', ''); - $sAdminLanguage = $this->oWizard->GetParameter('admin_language', 'EN US'); - $oPage->add('

Definition of the Administrator Account

'); - $oPage->add('
'); - $oPage->add('Administrator Account'); - $oPage->add(''); - $oPage->add(''); - $oPage->add(''); - $oPage->add(''); - $sSourceDir = APPROOT.'dictionaries/'; - $aLanguages = SetupUtils::GetAvailableLanguages($sSourceDir); - $oPage->add(''); - $oPage->add('
Login:
Password:
Confirm password:
Language: '); - $oPage->add(SetupUtils::GetLanguageSelect($sSourceDir, 'admin_language', $sAdminLanguage)); - $oPage->add('
'); - $oPage->add('
'); - $oPage->add_ready_script( - <<'); - } - else - { - $("#v_admin_user").html(''); - } - - bPasswordsMatch = ($('#admin_pwd').val() == $('#confirm_pwd').val()); - if (!bPasswordsMatch) - { - $('#v_admin_pwd').html(''); - } - else - { - $('#v_admin_pwd').html(''); - } - bRet = bPasswordsMatch && bRet; - - return bRet; -EOF - ; - } -} - -/** - * @since 3.0.0 N°4092 - */ -abstract class AbstractWizStepMiscParams extends WizardStep -{ - /** - * @since 3.0.0 N°4092 - */ - final protected function AddUseSymlinksFlagOption(WebPage $oPage): void - { - if (MFCompiler::CanUseSymbolicLinksFlagBeUsed()) { - $sChecked = (MFCompiler::IsUseSymbolicLinksFlagPresent()) ? ' checked' : ''; - - $oPage->add('
'); - $oPage->add('Dev parameters'); - $oPage->p('
'); - $oPage->add_ready_script( - <<<'JS' -$("#use-symbolic-links").on("click", function() { - var $this = $(this), - bUseSymbolicLinks = $this.prop("checked"); - var sAuthent = $('#authent_token').val(); - var oAjaxParams = { operation: 'toggle_use_symbolic_links', bUseSymbolicLinks: bUseSymbolicLinks, authent: sAuthent}; - $.post(GetAbsoluteUrlAppRoot()+'setup/ajax.dataloader.php', oAjaxParams); -}); -JS - ); - } - } - - final protected function AddForceUninstallFlagOption(WebPage $oPage): void - { - $sChecked = $this->oWizard->GetParameter('force-uninstall', false) ? ' checked ' : ''; - $oPage->add('
'); - $oPage->add('Advanced parameters'); - $oPage->p('
'); - - $oPage->add_ready_script( - <<<'JS' -$("#force-uninstall").on("click", function() { - let $this = $(this); - let bForceUninstall = $this.prop("checked"); - if( bForceUninstall && !confirm('Beware, uninstalling extensions flagged as non uninstallable may result in data corruption and application crashes. Are you sure you want to continue ?')){ - $this.prop("checked",false); - } -}); -JS - ); - } -} - -/** - * Miscellaneous Parameters (URL, Sample Data) when installing from scratch - */ -class WizStepInstallMiscParams extends AbstractWizStepMiscParams -{ - public function GetTitle() - { - return 'Miscellaneous Parameters'; - } - - public function GetPossibleSteps() - { - return ['WizStepModulesChoice']; - } - - public function ProcessParams($bMoveForward = true) - { - $this->oWizard->SaveParameter('default_language', ''); - $this->oWizard->SaveParameter('application_url', ''); - $this->oWizard->SaveParameter('graphviz_path', ''); - $this->oWizard->SaveParameter('sample_data', 'yes'); - return ['class' => 'WizStepModulesChoice', 'state' => 'start_install']; - } - - public function Display(WebPage $oPage) - { - $sDefaultLanguage = $this->oWizard->GetParameter('default_language', $this->oWizard->GetParameter('admin_language')); - $sApplicationURL = $this->oWizard->GetParameter('application_url', utils::GetDefaultUrlAppRoot(true)); - $sDefaultGraphvizPath = (strtolower(substr(PHP_OS, 0, 3)) === 'win') ? 'C:\\Program Files\\Graphviz\\bin\\dot.exe' : '/usr/bin/dot'; - $sGraphvizPath = $this->oWizard->GetParameter('graphviz_path', $sDefaultGraphvizPath); - $sSampleData = $this->oWizard->GetParameter('sample_data', 'yes'); - $oPage->add('

Additional parameters

'); - $oPage->add('
'); - $oPage->add('Default Language'); - $oPage->add(''); - $sSourceDir = APPROOT.'dictionaries/'; - $aLanguages = SetupUtils::GetAvailableLanguages($sSourceDir); - $oPage->add(''); - $oPage->add('
Default Language: '); - $oPage->add(SetupUtils::GetLanguageSelect($sSourceDir, 'default_language', $sDefaultLanguage)); - $oPage->add('
'); - $oPage->add('
'); - $oPage->add('
'); - $oPage->add('Application URL'); - $oPage->add(''); - $oPage->add(''); - $oPage->add('
URL:
'); - $oPage->add('
Change the value above if the end-users will be accessing the application by another path due to a specific configuration of the web server.
'); - $oPage->add('
'); - $oPage->add('
'); - $oPage->add('Path to Graphviz\' dot application'); - $oPage->add(''); - $oPage->add(''); - $oPage->add(''); - $oPage->add('
Path:
'); - $oPage->add(''); - $oPage->add('
'); - $oPage->add('
'); - $oPage->add('Sample Data'); - $sChecked = ($sSampleData == 'yes') ? 'checked ' : ''; - $oPage->p('
'); - $sAuthentToken = $this->oWizard->GetParameter('authent', ''); - $oPage->add(''); - $oPage->add_ready_script( - <<AddUseSymlinksFlagOption($oPage); - } - - public function AsyncAction(WebPage $oPage, $sCode, $aParameters) - { - switch ($sCode) { - case 'check_graphviz': - $sGraphvizPath = $aParameters['graphviz_path']; - $aCheck = SetupUtils::CheckGraphviz($sGraphvizPath); - - // N°2214 logging TRACE results - $aTraceCheck = CheckResult::FilterCheckResultArray($aCheck, [CheckResult::TRACE]); - foreach ($aTraceCheck as $oTraceCheck) { - SetupLog::Ok($oTraceCheck->sLabel); - } - - $aNonTraceCheck = array_diff($aCheck, $aTraceCheck); - foreach ($aNonTraceCheck as $oCheck) { - switch ($oCheck->iSeverity) { - case CheckResult::INFO: - $sStatus = 'ok'; - $sInfoExplanation = $oCheck->sLabel; - $sMessage = json_encode('
'.$sInfoExplanation.'
'); - - break; - - default: - case CheckResult::ERROR: - case CheckResult::WARNING: - $sStatus = 'ko'; - $sErrorExplanation = $oCheck->sLabel; - $sMessage = json_encode('
'.$sErrorExplanation.'
'); - break; - } - - if ($oCheck->iSeverity !== CheckResult::TRACE) { - $oPage->add_ready_script( - <<'); - } - else - { - $("#v_application_url").html(''); - } - bGraphviz = ($('#graphviz_path').val() != ''); - if (!bGraphviz) - { - // Does not prevent to move forward - $("#v_graphviz_path").html(''); - } - else - { - $("#v_graphviz_path").html(''); - } - return bRet; -EOF - ; - } -} - -/** - * Miscellaneous Parameters (URL...) in case of upgrade - */ -class WizStepUpgradeMiscParams extends AbstractWizStepMiscParams -{ - public function GetTitle() - { - return 'Miscellaneous Parameters'; - } - - public function GetPossibleSteps() - { - return ['WizStepModulesChoice']; - } - - public function ProcessParams($bMoveForward = true) - { - $this->oWizard->SaveParameter('application_url', ''); - $this->oWizard->SaveParameter('graphviz_path', ''); - $this->oWizard->SaveParameter('force-uninstall', false); - return ['class' => 'WizStepModulesChoice', 'state' => 'start_upgrade']; - } - - public function Display(WebPage $oPage) - { - $sApplicationURL = $this->oWizard->GetParameter('application_url', utils::GetAbsoluteUrlAppRoot(true)); //Preserve existing configuration (except for the str_replace based joker $SERVER_NAME$ which is lost) - $sDefaultGraphvizPath = (strtolower(substr(PHP_OS, 0, 3)) === 'win') ? 'C:\\Program Files\\Graphviz\\bin\\dot.exe' : '/usr/bin/dot'; - $sGraphvizPath = $this->oWizard->GetParameter('graphviz_path', $sDefaultGraphvizPath); - $oPage->add('

Additional parameters

'); - $oPage->add('
'); - $oPage->add('Application URL'); - $oPage->add(''); - $oPage->add(''); - $oPage->add('
URL:
'); - $oPage->add('
Change the value above if the end-users will be accessing the application by another path due to a specific configuration of the web server.
'); - $oPage->add('
'); - $oPage->add('
'); - $oPage->add('Path to Graphviz\' dot application'); - $oPage->add(''); - $oPage->add(''); - $oPage->add(''); - $oPage->add('
Path:
'); - $oPage->add(''); - $oPage->add('
'); - $sAuthentToken = $this->oWizard->GetParameter('authent', ''); - $oPage->add(''); - $oPage->add_ready_script( - <<AddUseSymlinksFlagOption($oPage); - $this->AddForceUninstallFlagOption($oPage); - } - - public function AsyncAction(WebPage $oPage, $sCode, $aParameters) - { - switch ($sCode) { - case 'check_graphviz': - $sGraphvizPath = $aParameters['graphviz_path']; - $aCheck = SetupUtils::CheckGraphviz($sGraphvizPath); - - // N°2214 logging TRACE results - $aTraceCheck = CheckResult::FilterCheckResultArray($aCheck, [CheckResult::TRACE]); - foreach ($aTraceCheck as $oTraceCheck) { - SetupLog::Ok($oTraceCheck->sLabel); - } - - $aNonTraceCheck = array_diff($aCheck, $aTraceCheck); - foreach ($aNonTraceCheck as $oCheck) { - switch ($oCheck->iSeverity) { - case CheckResult::INFO: - $sStatus = 'ok'; - $sInfoExplanation = $oCheck->sLabel; - $sMessage = json_encode('
'.$sInfoExplanation.'
'); - break; - - default: - case CheckResult::ERROR: - case CheckResult::WARNING: - $sStatus = 'ko'; - $sErrorExplanation = $oCheck->sLabel; - $sMessage = json_encode('
'.$sErrorExplanation.'
'); - break; - } - $oPage->add_ready_script( - <<'); - } - else - { - $("#v_application_url").html(''); - } - bGraphviz = ($('#graphviz_path').val() != ''); - if (!bGraphviz) - { - // Does not prevent to move forward - $("#v_graphviz_path").html(''); - } - else - { - $("#v_graphviz_path").html(''); - } - return bRet; -EOF - ; - } -} -/** - * Choice of the modules to be installed - */ -class WizStepModulesChoice extends WizardStep -{ - protected static string $SEP = '_'; - protected bool $bUpgrade = false; - protected bool $bCanMoveForward = true; - protected ?Config $oConfig = null; - - /** - * - * @var iTopExtensionsMap - */ - protected iTopExtensionsMap $oExtensionsMap; - - protected PhpExpressionEvaluator $oPhpExpressionEvaluator; - - /** - * Whether we were able to load the choices from the database or not - * @var bool - */ - protected bool $bChoicesFromDatabase; - - public function __construct(WizardController $oWizard, $sCurrentState) - { - parent::__construct($oWizard, $sCurrentState); - $this->bChoicesFromDatabase = false; - $this->oExtensionsMap = new iTopExtensionsMap(); - $sPreviousSourceDir = $this->oWizard->GetParameter('previous_version_dir', ''); - $sConfigPath = null; - if (($sPreviousSourceDir !== '') && is_readable($sPreviousSourceDir.'/conf/production/config-itop.php')) { - $sConfigPath = $sPreviousSourceDir.'/conf/production/config-itop.php'; - } elseif (is_readable(utils::GetConfigFilePath('production'))) { - $sConfigPath = utils::GetConfigFilePath('production'); - } - - // only called if the config file exists : we are updating a previous installation ! - // WARNING : we can't load this config directly, as it might be from another directory with a different approot_url (N°2684) - if ($sConfigPath !== null) { - $this->oConfig = new Config($sConfigPath); - - $aParamValues = $oWizard->GetParamForConfigArray(); - $this->oConfig->UpdateFromParams($aParamValues); - - $this->oExtensionsMap->LoadChoicesFromDatabase($this->oConfig); - $this->bChoicesFromDatabase = true; - } - } - - public function GetTitle() - { - $aStepInfo = $this->GetStepInfo(); - $sTitle = isset($aStepInfo['title']) ? $aStepInfo['title'] : 'Modules selection'; - return $sTitle; - } - - public function GetPossibleSteps() - { - return ['WizStepModulesChoice', 'WizStepSummary']; - } - - public function ProcessParams($bMoveForward = true) - { - // Accumulates the selected modules: - $index = $this->GetStepIndex(); - - // use json_encode:decode to store a hash array: step_id => array(input_name => selected_input_id) - $aSelectedChoices = json_decode($this->oWizard->GetParameter('selected_components', '{}'), true); - $aSelected = utils::ReadParam('choice', []); - $aSelectedChoices[$index] = $aSelected; - $this->oWizard->SetParameter('selected_components', json_encode($aSelectedChoices)); - - if ($this->GetStepInfo($index) == null) { - throw new Exception('Internal error: invalid step "'.$index.'" for the choice of modules.'); - } elseif ($bMoveForward) { - if ($this->GetStepInfo(1 + $index) != null) { - return ['class' => 'WizStepModulesChoice', 'state' => (1 + $index)]; - } else { - // Exiting this step of the wizard, let's convert the selection into a list of modules - $aModules = []; - $aExtensions = []; - $sDisplayChoices = '
    '; - for ($i = 0; $i <= $index; $i++) { - $aStepInfo = $this->GetStepInfo($i); - $sDisplayChoices .= $this->GetSelectedModules($aStepInfo, $aSelectedChoices[$i], $aModules, '', '', $aExtensions); - } - $sDisplayChoices .= '
'; - if (class_exists('CreateITILProfilesInstaller')) { - $this->oWizard->SetParameter('old_addon', true); - } - $this->oWizard->SetParameter('selected_modules', json_encode(array_keys($aModules))); - $this->oWizard->SetParameter('selected_extensions', json_encode($aExtensions)); - $this->oWizard->SetParameter('display_choices', $sDisplayChoices); - return ['class' => 'WizStepSummary', 'state' => '']; - } - - } - } - - public function Display(WebPage $oPage) - { - $this->DisplayStep($oPage); - } - - /** - * @param \SetupPage $oPage - * - * @throws \Exception - */ - protected function DisplayStep($oPage) - { - // Sanity check (not stopper, to let developers go further...) - try { - SetupUtils::AnalyzeInstallation($this->oWizard, true); - } catch (MissingDependencyException $e) { - $oPage->warning($e->getHtmlDesc(), $e->getMessage()); - } - - $this->bUpgrade = ($this->oWizard->GetParameter('install_mode') != 'install'); - $aStepInfo = $this->GetStepInfo(); - $oPage->add_style("div.choice { margin: 0.5em;}"); - $oPage->add_style("div.choice a { text-decoration:none; font-weight: bold; color: #1C94C4 }"); - $oPage->add_style("div.description { margin-left: 2em; }"); - $oPage->add_style(".choice-disabled { color: #999; }"); - $oPage->add_style("input.unremovable { accent-color: orangered;}"); - - $aModules = SetupUtils::AnalyzeInstallation($this->oWizard); - $sManualInstallError = SetupUtils::CheckManualInstallDirEmpty( - $aModules, - $this->oWizard->GetParameter('extensions_dir', 'extensions') - ); - if ($sManualInstallError !== '') { - $oPage->warning($sManualInstallError); - } - - $oPage->add('
'); - $sBannerPath = isset($aStepInfo['banner']) ? $aStepInfo['banner'] : ''; - if (!empty($sBannerPath)) { - if (substr($sBannerPath, 0, 1) == '/') { - // absolute path, means relative to APPROOT - $sBannerUrl = utils::GetDefaultUrlAppRoot(true).$sBannerPath; - } else { - // relative path: i.e. relative to the directory containing the XML file - $sFullPath = dirname($this->GetSourceFilePath()).'/'.$sBannerPath; - $sRealPath = realpath($sFullPath); - $sBannerUrl = utils::GetDefaultUrlAppRoot(true).str_replace(realpath(APPROOT), '', $sRealPath); - } - $oPage->add(''); - } - $sDescription = $aStepInfo['description'] ?? ''; - $oPage->add(''.$sDescription.''); - $oPage->add('
'); - - // Build the default choices - $aDefaults = $this->GetDefaults($aStepInfo, $aModules); - $index = $this->GetStepIndex(); - - // retrieve the saved selection - // use json_encode:decode to store a hash array: step_id => array(input_name => selected_input_id) - $aParameters = json_decode($this->oWizard->GetParameter('selected_components', '{}'), true); - if (!isset($aParameters[$index])) { - $aParameters[$index] = $aDefaults; - } - $aSelectedComponents = $aParameters[$index]; - - $oPage->add('
'); - $this->DisplayOptions($oPage, $aStepInfo, $aSelectedComponents, $aDefaults); - $oPage->add('
'); - - $oPage->add_script( - <<add_ready_script( - <<bChoicesFromDatabase) { - $this->GuessDefaultsFromModules($aInfo, $aDefaults, $aModules, $sParentId); - } else { - $this->GetDefaultsFromDatabase($aInfo, $aDefaults, $sParentId); - } - return $aDefaults; - } - - protected function GetDefaultsFromDatabase($aInfo, &$aDefaults, $sParentId) - { - $aOptions = isset($aInfo['options']) ? $aInfo['options'] : []; - foreach ($aOptions as $index => $aChoice) { - $sChoiceId = $sParentId.self::$SEP.$index; - if ($this->bUpgrade) { - if ($this->oExtensionsMap->IsMarkedAsChosen($aChoice['extension_code'])) { - $aDefaults[$sChoiceId] = $sChoiceId; - } - } elseif (isset($aChoice['default']) && $aChoice['default']) { - $aDefaults[$sChoiceId] = $sChoiceId; - } - // Recurse for sub_options (if any) - if (isset($aChoice['sub_options'])) { - $this->GetDefaultsFromDatabase($aChoice['sub_options'], $aDefaults, $sChoiceId); - } - } - - $aAlternatives = isset($aInfo['alternatives']) ? $aInfo['alternatives'] : []; - $sChoiceName = null; - foreach ($aAlternatives as $index => $aChoice) { - $sChoiceId = $sParentId.self::$SEP.$index; - if ($sChoiceName == null) { - $sChoiceName = $sChoiceId; // All radios share the same name - } - if ($this->bUpgrade) { - if ($this->oExtensionsMap->IsMarkedAsChosen($aChoice['extension_code'])) { - $aDefaults[$sChoiceName] = $sChoiceId; - } - } elseif (isset($aChoice['default']) && $aChoice['default']) { - $aDefaults[$sChoiceName] = $sChoiceId; - } - // Recurse for sub_options (if any) - if (isset($aChoice['sub_options'])) { - $this->GetDefaultsFromDatabase($aChoice['sub_options'], $aDefaults, $sChoiceId); - } - } - } - - /** - * Try to guess the user choices based on the current list of installed modules... - * @param array $aInfo - * @param array $aDefaults - * @param array $aModules - * @param string $sParentId - * @return array - */ - protected function GuessDefaultsFromModules($aInfo, &$aDefaults, $aModules, $sParentId = '') - { - $aRetScore = []; - $aScores = []; - - $aOptions = isset($aInfo['options']) ? $aInfo['options'] : []; - foreach ($aOptions as $index => $aChoice) { - $sChoiceId = $sParentId.self::$SEP.$index; - $aScores[$sChoiceId] = []; - if (!$this->bUpgrade && isset($aChoice['default']) && $aChoice['default']) { - $aDefaults[$sChoiceId] = $sChoiceId; - } - if ($this->bUpgrade) { - // In upgrade mode, the defaults are the installed modules - foreach ($aChoice['modules'] as $sModuleId) { - if ($aModules[$sModuleId]['version_db'] != '') { - // A module corresponding to this choice is installed - $aScores[$sChoiceId][$sModuleId] = true; - } - } - // Used for migration from 1.3.x or before - // Accept that the new version can have one new module than the previous version - // The option is still selected - $iSelected = count($aScores[$sChoiceId]); - $iNeeded = count($aChoice['modules']); - if (($iSelected > 0) && (($iNeeded - $iSelected) < 2)) { - // All the modules are installed, this choice is selected - $aDefaults[$sChoiceId] = $sChoiceId; - } - $aRetScore = array_merge($aRetScore, $aScores[$sChoiceId]); - } - - if (isset($aChoice['sub_options'])) { - $aScores[$sChoiceId] = array_merge($aScores[$sChoiceId], $this->GuessDefaultsFromModules($aChoice['sub_options'], $aDefaults, $sChoiceId)); - } - $index++; - } - - $aAlternatives = isset($aInfo['alternatives']) ? $aInfo['alternatives'] : []; - $sChoiceName = null; - $sChoiceIdNone = null; - foreach ($aAlternatives as $index => $aChoice) { - $sChoiceId = $sParentId.self::$SEP.$index; - $aScores[$sChoiceId] = []; - if ($sChoiceName == null) { - $sChoiceName = $sChoiceId; - } - if (!$this->bUpgrade && isset($aChoice['default']) && $aChoice['default']) { - $aDefaults[$sChoiceName] = $sChoiceId; - } - if (isset($aChoice['sub_options'])) { - // By default (i.e. install-mode), sub options can only be checked if the parent option is checked by default - if ($this->bUpgrade || (isset($aChoice['default']) && $aChoice['default'])) { - $aScores[$sChoiceId] = $this->GuessDefaultsFromModules($aChoice['sub_options'], $aDefaults, $aModules, $sChoiceId); - } - } - $index++; - } - - $iMaxScore = 0; - if ($this->bUpgrade && (count($aAlternatives) > 0)) { - // The installed choices have precedence over the 'default' choices - // In case several choices share the same base modules, let's weight the alternative choices - // based on their number of installed modules - $sChoiceName = null; - - foreach ($aAlternatives as $index => $aChoice) { - $sChoiceId = $sParentId.self::$SEP.$index; - if ($sChoiceName == null) { - $sChoiceName = $sChoiceId; - } - if (array_key_exists('modules', $aChoice)) { - foreach ($aChoice['modules'] as $sModuleId) { - if ($aModules[$sModuleId]['version_db'] != '') { - // A module corresponding to this choice is installed, increase the score of this choice - if (!isset($aScores[$sChoiceId])) { - $aScores[$sChoiceId] = []; - } - $aScores[$sChoiceId][$sModuleId] = true; - $iMaxScore = max($iMaxScore, count($aScores[$sChoiceId])); - } - } - //if (count($aScores[$sChoiceId]) == count($aChoice['modules'])) - //{ - // $iScore += 100; // Bonus for the parent when a choice is complete - //} - $aRetScore = array_merge($aRetScore, $aScores[$sChoiceId]); - } - $iMaxScore = max($iMaxScore, isset($aScores[$sChoiceId]) ? count($aScores[$sChoiceId]) : 0); - } - } - if ($iMaxScore > 0) { - $aNumericScores = []; - foreach ($aScores as $sChoiceId => $aModules) { - $aNumericScores[$sChoiceId] = count($aModules); - } - // The choice with the bigger score wins ! - asort($aNumericScores, SORT_NUMERIC); - $aKeys = array_keys($aNumericScores); - $sBetterChoiceId = array_pop($aKeys); - $aDefaults[$sChoiceName] = $sBetterChoiceId; - } - // echo "Scores:
".print_r($aScores, true)."

"; - // echo "Defaults:
".print_r($aDefaults, true)."

"; - return $aRetScore; - } - - private function GetPhpExpressionEvaluator(): PhpExpressionEvaluator - { - if (!isset($this->oPhpExpressionEvaluator)) { - $this->oPhpExpressionEvaluator = new PhpExpressionEvaluator([], RunTimeEnvironment::STATIC_CALL_AUTOSELECT_WHITELIST); - } - - return $this->oPhpExpressionEvaluator; - } - - /** - * Converts the list of selected "choices" into a list of "modules": take into account the selected and the mandatory modules - * - * @param array $aInfo Info about the "choice" array('options' => array(...), 'alternatives' => array(...)) - * @param array $aSelectedChoices List of selected choices array('name' => 'selected_value_id') - * @param array $aModules Return parameter: List of selected modules array('module_id' => true) - * @param string $sParentId Used for recursion - * - * @return string A text representation of what will be installed - */ - protected function GetSelectedModules($aInfo, $aSelectedChoices, &$aModules, $sParentId = '', $sDisplayChoices = '', &$aSelectedExtensions = null) - { - if ($sParentId == '') { - // Check once (before recursing) that the hidden modules are selected - foreach (SetupUtils::AnalyzeInstallation($this->oWizard) as $sModuleId => $aModule) { - if (($sModuleId != ROOT_MODULE) && !isset($aModules[$sModuleId])) { - if (($aModule['category'] == 'authentication') || (!$aModule['visible'] && !isset($aModule['auto_select']))) { - $aModules[$sModuleId] = true; - $sDisplayChoices .= '
  • '.$aModule['label'].' (hidden)
  • '; - } - } - } - } - $aOptions = isset($aInfo['options']) ? $aInfo['options'] : []; - foreach ($aOptions as $index => $aChoice) { - $sChoiceId = $sParentId.self::$SEP.$index; - $aModuleInfo = []; - // Get the extension corresponding to the choice - foreach ($this->oExtensionsMap->GetAllExtensions() as $sExtensionVersion => $oExtension) { - if (utils::StartsWith($sExtensionVersion, $aChoice['extension_code'].'/')) { - $aModuleInfo = $oExtension->aModuleInfo; - break; - } - } - if ((isset($aChoice['mandatory']) && $aChoice['mandatory']) || - (isset($aSelectedChoices[$sChoiceId]) && ($aSelectedChoices[$sChoiceId] == $sChoiceId))) { - $sDisplayChoices .= '
  • '.$aChoice['title'].'
  • '; - if (isset($aChoice['modules'])) { - foreach ($aChoice['modules'] as $sModuleId) { - $bSelected = true; - if (isset($aModuleInfo[$sModuleId])) { - // Test if module has 'auto_select' - $aInfo = $aModuleInfo[$sModuleId]; - if (isset($aInfo['auto_select'])) { - // Check the module selection - try { - SetupInfo::SetSelectedModules($aModules); - $bSelected = $this->GetPhpExpressionEvaluator()->ParseAndEvaluateBooleanExpression($aInfo['auto_select']); - } catch (ModuleFileReaderException $e) { - //logged already - $bSelected = false; - } - } - } - if ($bSelected) { - $aModules[$sModuleId] = true; // store the Id of the selected module - SetupInfo::SetSelectedModules($aModules); - } - } - } - $sChoiceType = isset($aChoice['type']) ? $aChoice['type'] : 'wizard_option'; - if ($aSelectedExtensions !== null) { - $aSelectedExtensions[] = $aChoice['extension_code']; - } - // Recurse only for selected choices - if (isset($aChoice['sub_options'])) { - $sDisplayChoices .= '
      '; - $sDisplayChoices = $this->GetSelectedModules($aChoice['sub_options'], $aSelectedChoices, $aModules, $sChoiceId, $sDisplayChoices, $aSelectedExtensions); - $sDisplayChoices .= '
    '; - } - $sDisplayChoices .= ''; - } - } - - $aAlternatives = isset($aInfo['alternatives']) ? $aInfo['alternatives'] : []; - $sChoiceName = null; - foreach ($aAlternatives as $index => $aChoice) { - $sChoiceId = $sParentId.self::$SEP.$index; - if ($sChoiceName == null) { - $sChoiceName = $sChoiceId; - } - if ((isset($aChoice['mandatory']) && $aChoice['mandatory']) || - (isset($aSelectedChoices[$sChoiceName]) && ($aSelectedChoices[$sChoiceName] == $sChoiceId))) { - $sDisplayChoices .= '
  • '.$aChoice['title'].'
  • '; - if ($aSelectedExtensions !== null) { - $aSelectedExtensions[] = $aChoice['extension_code']; - } - if (isset($aChoice['modules'])) { - foreach ($aChoice['modules'] as $sModuleId) { - $aModules[$sModuleId] = true; // store the Id of the selected module - } - } - // Recurse only for selected choices - if (isset($aChoice['sub_options'])) { - $sDisplayChoices .= '
      '; - $sDisplayChoices = $this->GetSelectedModules($aChoice['sub_options'], $aSelectedChoices, $aModules, $sChoiceId, $sDisplayChoices, $aSelectedExtensions); - $sDisplayChoices .= '
    '; - } - $sDisplayChoices .= ''; - } - } - if ($sParentId == '') { - // Last pass (after all the user's choices are turned into "selected" modules): - // Process 'auto_select' modules for modules that are not already selected - $aAvailableModules = SetupUtils::AnalyzeInstallation($this->oWizard); - do { - // Loop while new modules are added... - $bModuleAdded = false; - foreach ($aAvailableModules as $sModuleId => $aModule) { - if (($sModuleId != ROOT_MODULE) && !array_key_exists($sModuleId, $aModules) && isset($aModule['auto_select'])) { - try { - SetupInfo::SetSelectedModules($aModules); - $bSelected = $this->GetPhpExpressionEvaluator()->ParseAndEvaluateBooleanExpression($aModule['auto_select']); - if ($bSelected) { - $aModules[$sModuleId] = true; // store the Id of the selected module - $sDisplayChoices .= '
  • '.$aModule['label'].' (auto_select)
  • '; - $bModuleAdded = true; - } - } catch (ModuleFileReaderException $e) { - //logged already - $sDisplayChoices .= '
  • Warning: auto_select failed with exception ('.$e->getMessage().') for module "'.$sModuleId.'"
  • '; - } - } - } - } while ($bModuleAdded); - } - - return $sDisplayChoices; - } - - protected function GetStepIndex() - { - switch ($this->sCurrentState) { - case 'start_install': - case 'start_upgrade': - $index = 0; - break; - - default: - $index = (int)$this->sCurrentState; - } - return $index; - } - - protected function GetStepInfo($idx = null) - { - $aStepInfo = null; - if ($idx === null) { - $index = $this->GetStepIndex(); - } else { - $index = $idx; - } - - $aSteps = []; - $this->oWizard->SetParameter('additional_extensions_modules', json_encode([])); // Default value, no additional extensions - - if (@file_exists($this->GetSourceFilePath())) { - // Found an "installation.xml" file, let's use this definition for the wizard - $aParams = new XMLParameters($this->GetSourceFilePath()); - $aSteps = $aParams->Get('steps', []); - - // Additional step for the "extensions" - $aStepDefinition = [ - 'title' => 'Extensions', - 'description' => '

    Select additional extensions to install. You can launch the installation again to install new extensions or remove installed ones.

    ', - 'banner' => '/images/icons/icons8-puzzle.svg', - 'options' => [], - ]; - - foreach ($this->oExtensionsMap->GetAllExtensionsWithPreviouslyInstalled() as $oExtension) { - if (($oExtension->sSource !== iTopExtension::SOURCE_WIZARD) && ($oExtension->bVisible) && (count($oExtension->aMissingDependencies) == 0)) { - $aStepDefinition['options'][] = [ - 'extension_code' => $oExtension->sCode, - 'title' => $oExtension->sLabel, - 'description' => $oExtension->sDescription, - 'more_info' => $oExtension->sMoreInfoUrl, - 'default' => true, // by default offer to install all modules - 'modules' => $oExtension->aModules, - 'mandatory' => $oExtension->bMandatory || ($oExtension->sSource === iTopExtension::SOURCE_REMOTE), - 'source_label' => $this->GetExtensionSourceLabel($oExtension->sSource), - 'uninstallable' => $oExtension->CanBeUninstalled(), - 'missing' => $oExtension->bRemovedFromDisk, - ]; - } - } - - // Display this step of the wizard only if there is something to display - if (count($aStepDefinition['options']) !== 0) { - $aSteps[] = $aStepDefinition; - $this->oWizard->SetParameter('additional_extensions_modules', json_encode($aStepDefinition['options'])); - } - } else { - // No wizard configuration provided, build a standard one with just one big list. All items are mandatory, only works when there are no conflicted modules. - $aStepDefinition = [ - 'title' => 'Modules Selection', - 'description' => '

    Select the modules to install. You can launch the installation again to install new modules, but you cannot remove already installed modules.

    ', - 'banner' => '/images/icons/icons8-apps-tab.svg', - 'options' => [], - ]; - foreach ($this->oExtensionsMap->GetAllExtensions() as $oExtension) { - if (($oExtension->bVisible) && (count($oExtension->aMissingDependencies) == 0)) { - $aStepDefinition['options'][] = [ - 'extension_code' => $oExtension->sCode, - 'title' => $oExtension->sLabel, - 'description' => $oExtension->sDescription, - 'more_info' => $oExtension->sMoreInfoUrl, - 'default' => true, // by default offer to install all modules - 'modules' => $oExtension->aModules, - 'mandatory' => $oExtension->bMandatory || ($oExtension->sSource !== iTopExtension::SOURCE_REMOTE), - 'source_label' => $this->GetExtensionSourceLabel($oExtension->sSource), - ]; - } - } - $aSteps[] = $aStepDefinition; - } - - if (array_key_exists($index, $aSteps)) { - $aStepInfo = $aSteps[$index]; - } - - return $aStepInfo; - } - - protected function GetExtensionSourceLabel($sSource) - { - $sDecorationClass = ''; - switch ($sSource) { - case iTopExtension::SOURCE_MANUAL: - $sResult = 'Local extensions folder'; - $sDecorationClass = 'fas fa-folder'; - break; - - case iTopExtension::SOURCE_REMOTE: - $sResult = (ITOP_APPLICATION == 'iTop') ? 'iTop Hub' : 'ITSM Designer'; - $sDecorationClass = (ITOP_APPLICATION == 'iTop') ? 'fc fc-chameleon-icon' : 'fa pencil-ruler'; - break; - - default: - $sResult = ''; - } - if ($sResult == '') { - return ''; - } - return ''; - } - - protected function DisplayOptions($oPage, $aStepInfo, $aSelectedComponents, $aDefaults, $sParentId = '', $bAllDisabled = false) - { - $aOptions = isset($aStepInfo['options']) ? $aStepInfo['options'] : []; - $aAlternatives = isset($aStepInfo['alternatives']) ? $aStepInfo['alternatives'] : []; - - $bDisableUninstallCheck = (bool)$this->oWizard->GetParameter('force-uninstall', false); - - foreach ($aOptions as $index => $aChoice) { - $sChoiceId = $sParentId.self::$SEP.$index; - $sDataId = 'data-id="'.utils::EscapeHtml($aChoice['extension_code']).'"'; - $sId = utils::EscapeHtml($aChoice['extension_code']); - $bIsDefault = array_key_exists($sChoiceId, $aDefaults); - - $oITopExtension = $this->oExtensionsMap->GetFromExtensionCode($aChoice['extension_code']); - $bCanBeUninstalled = isset($aChoice['uninstallable']) ? $aChoice['uninstallable'] : $oITopExtension->CanBeUninstalled(); - $bSelected = isset($aSelectedComponents[$sChoiceId]) && ($aSelectedComponents[$sChoiceId] == $sChoiceId); - $bMandatory = (isset($aChoice['mandatory']) && $aChoice['mandatory']) || $this->bUpgrade && $bIsDefault && !$bCanBeUninstalled && !$bDisableUninstallCheck; - ; - $bMissingFromDisk = isset($aChoice['missing']) && $aChoice['missing'] === true; - $bInstalled = $bMissingFromDisk || $oITopExtension->bInstalled; - $bDisabled = $bMandatory || $bAllDisabled || $bMissingFromDisk; - $bChecked = $bMandatory || $bSelected; - - $sTooltip = ''; - $sUnremovable = ''; - if ($bMissingFromDisk) { - $sTooltip .= 'source removed'; - } - if ($bInstalled) { - $sTooltip .= 'installed'; - $sTooltip .= 'to be uninstalled'; - } else { - $sTooltip .= 'to be installed'; - $sTooltip .= 'not installed'; - } - if (!$bCanBeUninstalled) { - $sTooltip .= 'cannot be uninstalled'; - } - if ($bDisabled && !$bChecked && !$bCanBeUninstalled && !$bDisableUninstallCheck) { - $this->bCanMoveForward = false;//Disable "Next" - } - $sChecked = $bChecked ? ' checked ' : ''; - $sDisabled = $bDisabled ? ' disabled data-disabled="disabled" ' : ''; - $sMissingModule = $bMissingFromDisk ? 'setup-extension--missing' : ''; - - $sHiddenInput = $bDisabled && $bChecked ? '' : ''; - $oPage->add('
    '.$sHiddenInput.' '); - $this->DisplayChoice($oPage, $aChoice, $aSelectedComponents, $aDefaults, $sChoiceId, $bDisabled, $sTooltip); - $oPage->add('
    '); - } - $sChoiceName = null; - $sDisabled = ''; - $bDisabled = false; - $sChoiceIdNone = null; - foreach ($aAlternatives as $index => $aChoice) { - $sChoiceId = $sParentId.self::$SEP.$index; - if ($sChoiceName == null) { - $sChoiceName = $sChoiceId; // All radios share the same name - } - $bIsDefault = array_key_exists($sChoiceName, $aDefaults) && ($aDefaults[$sChoiceName] == $sChoiceId); - $bMandatory = (isset($aChoice['mandatory']) && $aChoice['mandatory']) || ($this->bUpgrade && $bIsDefault); - if ($bMandatory || $bAllDisabled) { - // One choice is mandatory, all alternatives are disabled - $sDisabled = ' disabled data-disabled="disabled"'; - $bDisabled = true; - } - if ((!isset($aChoice['sub_options']) || (count($aChoice['sub_options']) == 0)) && (!isset($aChoice['modules']) || (count($aChoice['modules']) == 0))) { - $sChoiceIdNone = $sChoiceId; // the "None" / empty choice - } - } - - if (!array_key_exists($sChoiceName, $aDefaults) || ($aDefaults[$sChoiceName] == $sChoiceIdNone)) { - // The "none" choice does not disable the selection !! - $sDisabled = ''; - $bDisabled = false; - } - - foreach ($aAlternatives as $index => $aChoice) { - $sAttributes = ''; - $sChoiceId = $sParentId.self::$SEP.$index; - $sDataId = 'data-id="'.utils::EscapeHtml($aChoice['extension_code']).'"'; - $sId = utils::EscapeHtml($aChoice['extension_code']); - - if ($sChoiceName == null) { - $sChoiceName = $sChoiceId; // All radios share the same name - } - $bIsDefault = array_key_exists($sChoiceName, $aDefaults) && ($aDefaults[$sChoiceName] == $sChoiceId); - $bSelected = isset($aSelectedComponents[$sChoiceName]) && ($aSelectedComponents[$sChoiceName] == $sChoiceId); - if (!isset($aSelectedComponents[$sChoiceName]) && ($sChoiceIdNone != null)) { - // No choice selected, select the "None" option - $bSelected = ($sChoiceId == $sChoiceIdNone); - } - $bMandatory = (isset($aChoice['mandatory']) && $aChoice['mandatory']) || ($this->bUpgrade && $bIsDefault); - - if ($bSelected) { - $sAttributes = ' checked '; - } - $sHidden = ''; - if ($bMandatory && $bDisabled) { - $sAttributes = ' checked '; - $sHidden = ''; - } - $oPage->add('
    '.$sHidden.' '); - $this->DisplayChoice($oPage, $aChoice, $aSelectedComponents, $aDefaults, $sChoiceId, $bDisabled && !$bSelected); - $oPage->add('
    '); - } - } - - protected function DisplayChoice($oPage, $aChoice, $aSelectedComponents, $aDefaults, $sChoiceId, $bDisabled = false, $sTooltip = '') - { - $sMoreInfo = (isset($aChoice['more_info']) && ($aChoice['more_info'] != '')) ? 'More information' : ''; - $sSourceLabel = $aChoice['source_label'] ?? ''; - $sId = utils::EscapeHtml($aChoice['extension_code']); - - $oPage->add(' '.$sMoreInfo.''); - $sDescription = isset($aChoice['description']) ? utils::EscapeHtml($aChoice['description']) : ''; - $oPage->add('
    '.$sDescription.''); - if (isset($aChoice['sub_options'])) { - $this->DisplayOptions($oPage, $aChoice['sub_options'], $aSelectedComponents, $aDefaults, $sChoiceId, $bDisabled); - } - $oPage->add('
    '); - } - - protected function GetSourceFilePath() - { - $sSourceDir = $this->oWizard->GetParameter('source_dir'); - return $sSourceDir.'/installation.xml'; - } - - public function CanMoveForward() - { - return true; - } - - public function JSCanMoveForward() - { - - return $this->bCanMoveForward ? 'return true;' : 'return false;'; - } - - public function GetNextButtonLabel() - { - return $this->bCanMoveForward ? 'Next' : 'Non-uninstallable extension missing'; - } - -} - -/** - * Summary of the installation tasks - */ -class WizStepSummary extends WizardStep -{ - protected $bDependencyCheck = null; - protected $sDependencyIssue = null; - - protected function CheckDependencies() - { - if (is_null($this->bDependencyCheck)) { - $aSelectedModules = json_decode($this->oWizard->GetParameter('selected_modules'), true); - $this->bDependencyCheck = true; - try { - SetupUtils::AnalyzeInstallation($this->oWizard, true, $aSelectedModules); - } catch (MissingDependencyException $e) { - $this->bDependencyCheck = false; - $this->sDependencyIssue = $e->getHtmlDesc(); - } - } - return $this->bDependencyCheck; - } - - public function GetTitle() - { - $sMode = $this->oWizard->GetParameter('mode', 'install'); - if ($sMode == 'install') { - return 'Ready to install'; - - } else { - return 'Ready to upgrade'; - } - } - - public function GetPossibleSteps() - { - return ['WizStepDone']; - } - - /** - * Returns the label for the " Next >> " button - * @return string The label for the button - */ - public function GetNextButtonLabel() - { - return 'Install'; - } - - public function CanMoveForward() - { - if ($this->CheckDependencies()) { - return true; - } else { - return false; - } - } - - public function ProcessParams($bMoveForward = true) - { - return ['class' => 'WizStepDone', 'state' => '']; - } - - public function Display(WebPage $oPage) - { - - $aInstallParams = $this->BuildConfig(); - - $sMode = $aInstallParams['mode']; - - $sDestination = ITOP_APPLICATION.(($sMode == 'install') ? ' version '.ITOP_VERSION.' is about to be installed ' : ' is about to be upgraded '); - $sDBDescription = ' existing database '.$aInstallParams['database']['name'].''; - if (($sMode == 'install') && ($this->oWizard->GetParameter('create_db') == 'yes')) { - $sDBDescription = ' new database '.$aInstallParams['database']['name'].''; - } - $sDestination .= 'into the '.$sDBDescription.' on the server '.$aInstallParams['database']['server'].'.'; - $oPage->add('

    '.$sDestination.'

    '); - - $oPage->add('
    Installation Parameters'); - $oPage->add('
    '); - $oPage->add('
    Database Parameters
      '); - $oPage->add('
    • Server Name: '.$aInstallParams['database']['server'].'
    • '); - $oPage->add('
    • DB User Name: '.$aInstallParams['database']['user'].'
    • '); - $oPage->add('
    • DB user password: ***
    • '); - if (($sMode == 'install') && ($this->oWizard->GetParameter('create_db') == 'yes')) { - $oPage->add('
    • Database Name: '.$aInstallParams['database']['name'].' (will be created)
    • '); - } else { - $oPage->add('
    • Database Name: '.$aInstallParams['database']['name'].'
    • '); - } - if ($aInstallParams['database']['prefix'] != '') { - $oPage->add('
    • Prefix for the '.ITOP_APPLICATION.' tables: '.$aInstallParams['database']['prefix'].'
    • '); - } else { - $oPage->add('
    • Prefix for the '.ITOP_APPLICATION.' tables: none
    • '); - } - $oPage->add('
    '); - - $oPage->add('
    Data Model Configuration'); - $oPage->add($this->oWizard->GetParameter('display_choices')); - $oPage->add('
    '); - - $oPage->add('
    Other Parameters
      '); - if ($sMode == 'install') { - $oPage->add('
    • Default language: '.$aInstallParams['language'].'
    • '); - } - - $oPage->add('
    • URL to access the application: '.$aInstallParams['url'].'
    • '); - $oPage->add('
    • Graphviz\' dot path: '.$aInstallParams['graphviz_path'].'
    • '); - if ($aInstallParams['sample_data'] == 'yes') { - $oPage->add('
    • Sample data will be loaded into the database.
    • '); - } - if ($aInstallParams['old_addon']) { - $oPage->add('
    • Compatibility mode: Using the version 1.2 of the UserRightsProfiles add-on.
    • '); - } - $oPage->add('
    '); - - if ($sMode == 'install') { - $oPage->add('
    Admininistrator Account
      '); - $oPage->add('
    • Login: '.$aInstallParams['admin_account']['user'].'
    • '); - $oPage->add('
    • Password: '.$aInstallParams['admin_account']['pwd'].'
    • '); - $oPage->add('
    • Language: '.$aInstallParams['admin_account']['language'].'
    • '); - $oPage->add('
    '); - } - - $aMiscOptions = $aInstallParams['options']; - if (count($aMiscOptions) > 0) { - $oPage->add('
    Miscellaneous Options
      '); - foreach ($aMiscOptions as $sKey => $sValue) { - $oPage->add('
    • '.$sKey.': '.$sValue.'
    • '); - } - $oPage->add('
    '); - - } - - $aSelectedModules = $aInstallParams['selected_modules']; - - if (isset($aMiscOptions['generate_config'])) { - $oDoc = new DOMDocument('1.0', 'UTF-8'); - $oDoc->preserveWhiteSpace = false; - $oDoc->formatOutput = true; - $oParams = new PHPParameters(); - $oParams->LoadFromHash($aInstallParams); - $oParams->ToXML($oDoc, null, 'installation'); - $sXML = $oDoc->saveXML(); - $oPage->add('
    XML Config file
      ');
      -			$oPage->add(utils::EscapeHtml($sXML));
      -			$oPage->add('
    '); - } - - $oPage->add('
    '); // params_summary - $oPage->add('
    '); - - $oPage->add('
    Progress of the installation'); - $oPage->add('
    '); - $oPage->LinkScriptFromAppRoot('setup/jquery.progression.js'); - $oPage->add('

    Ready to start...

    0%
    '); - $oPage->add('
    '); // progress_content - $oPage->add('
    '); - - $sJSONData = json_encode($aInstallParams); - $oPage->add(''); - - $sAuthentToken = $this->oWizard->GetParameter('authent', ''); - $oPage->add(''); - - if (!$this->CheckDependencies()) { - $oPage->error($this->sDependencyIssue); - } - - $oPage->add_ready_script( - <<oWizard->GetParameter('install_mode', 'install'); - $aSelectedModules = json_decode($this->oWizard->GetParameter('selected_modules'), true); - $aSelectedExtensions = json_decode($this->oWizard->GetParameter('selected_extensions'), true); - $sBackupDestination = ''; - $sPreviousConfigurationFile = ''; - $sDBName = $this->oWizard->GetParameter('db_name'); - if ($sMode == 'upgrade') { - $sPreviousVersionDir = $this->oWizard->GetParameter('previous_version_dir', ''); - if (!empty($sPreviousVersionDir)) { - $aPreviousInstance = SetupUtils::GetPreviousInstance($sPreviousVersionDir); - if ($aPreviousInstance['found']) { - $sPreviousConfigurationFile = $aPreviousInstance['configuration_file']; - } - } - - if ($this->oWizard->GetParameter('db_backup', false)) { - $sBackupDestination = $this->oWizard->GetParameter('db_backup_path', ''); - } - } else { - - $sDBNewName = $this->oWizard->GetParameter('db_new_name', ''); - if ($sDBNewName != '') { - $sDBName = $sDBNewName; // Database will be created - } - } - - $sSourceDir = $this->oWizard->GetParameter('source_dir'); - $aCopies = []; - if (($sMode == 'upgrade') && ($this->oWizard->GetParameter('upgrade_type') == 'keep-previous')) { - $sPreviousVersionDir = $this->oWizard->GetParameter('previous_version_dir'); - $aCopies[] = ['source' => $sSourceDir, 'destination' => 'modules']; // Source is an absolute path, destination is relative to APPROOT - $aCopies[] = ['source' => $sPreviousVersionDir.'/portal', 'destination' => 'portal']; // Source is an absolute path, destination is relative to APPROOT - $sSourceDir = APPROOT.'modules'; - } - - $aInstallParams = [ - 'mode' => $sMode, - 'preinstall' => [ - 'copies' => $aCopies, - // 'backup' => see below - ], - 'source_dir' => str_replace(APPROOT, '', $sSourceDir), - 'datamodel_version' => $this->oWizard->GetParameter('datamodel_version'), //TODO: let the installer compute this automatically... - 'previous_configuration_file' => $sPreviousConfigurationFile, - 'extensions_dir' => 'extensions', - 'target_env' => 'production', - 'workspace_dir' => '', - 'database' => [ - 'server' => $this->oWizard->GetParameter('db_server'), - 'user' => $this->oWizard->GetParameter('db_user'), - 'pwd' => $this->oWizard->GetParameter('db_pwd'), - 'name' => $sDBName, - 'db_tls_enabled' => $this->oWizard->GetParameter('db_tls_enabled'), - 'db_tls_ca' => $this->oWizard->GetParameter('db_tls_ca'), - 'prefix' => $this->oWizard->GetParameter('db_prefix'), - ], - 'url' => $this->oWizard->GetParameter('application_url'), - 'graphviz_path' => $this->oWizard->GetParameter('graphviz_path'), - 'admin_account' => [ - 'user' => $this->oWizard->GetParameter('admin_user'), - 'pwd' => $this->oWizard->GetParameter('admin_pwd'), - 'language' => $this->oWizard->GetParameter('admin_language'), - ], - 'language' => $this->oWizard->GetParameter('default_language'), - 'selected_modules' => $aSelectedModules, - 'selected_extensions' => $aSelectedExtensions, - 'sample_data' => ($this->oWizard->GetParameter('sample_data', '') == 'yes') ? true : false , - 'old_addon' => $this->oWizard->GetParameter('old_addon', false), // whether or not to use the "old" userrights profile addon - 'options' => json_decode($this->oWizard->GetParameter('misc_options', '[]'), true), - 'mysql_bindir' => $this->oWizard->GetParameter('mysql_bindir'), - ]; - - if ($sBackupDestination != '') { - $aInstallParams['preinstall']['backup'] = [ - 'destination' => $sBackupDestination, - 'configuration_file' => $sPreviousConfigurationFile, - ]; - } - - return $aInstallParams; - } - - public function AsyncAction(WebPage $oPage, $sCode, $aParameters) - { - $oParameters = new PHPParameters(); - $sStep = $aParameters['installer_step']; - $sJSONParameters = $aParameters['installer_config']; - $oParameters->LoadFromHash(json_decode($sJSONParameters, true /* bAssoc */)); - $oInstaller = new ApplicationInstaller($oParameters); - $aRes = $oInstaller->ExecuteStep($sStep); - if (($aRes['status'] != ApplicationInstaller::ERROR) && ($aRes['next-step'] != '')) { - // Tell the web page to move the progress bar and to launch the next step - $sMessage = addslashes(utils::EscapeHtml($aRes['next-step-label'])); - $oPage->add_ready_script( - <<{$aRes['next-step-label']}'); - ExecuteStep('{$aRes['next-step']}'); -EOF - ); - } elseif ($aRes['status'] != ApplicationInstaller::ERROR) { - // Installation complete, move to the next step of the wizard - $oPage->add_ready_script( - <<', $sMessage); - $oPage->add_ready_script( - << '', 'state' => '']; - } - - public function Display(WebPage $oPage) - { - // Check if there are some manual steps required: - $aManualSteps = []; - $aAvailableModules = SetupUtils::AnalyzeInstallation($this->oWizard); - - $sRootUrl = utils::GetAbsoluteUrlAppRoot(true); - $aSelectedModules = json_decode($this->oWizard->GetParameter('selected_modules'), true); - foreach ($aSelectedModules as $sModuleId) { - if (!empty($aAvailableModules[$sModuleId]['doc.manual_setup'])) { - $sUrl = $aAvailableModules[$sModuleId]['doc.manual_setup']; - $sManualStepUrl = utils::IsURL($sUrl) ? $sUrl : $sRootUrl.$sUrl; - $aManualSteps[$aAvailableModules[$sModuleId]['label']] = $sManualStepUrl; - } - } - $oPage->add('
    '); - if (count($aManualSteps) > 0) { - $oPage->add("

    Manual operations required

    "); - $oPage->p("In order to complete the installation, the following manual operations are required:"); - foreach ($aManualSteps as $sModuleLabel => $sUrl) { - $oPage->p("Manual instructions for $sModuleLabel"); - } - $oPage->add("

    Congratulations for installing ".ITOP_APPLICATION."

    "); - } else { - $oPage->add("

    Congratulations for installing ".ITOP_APPLICATION."

    "); - $oPage->ok("The installation completed successfully."); - } - - $bHasBackup = false; - if (($this->oWizard->GetParameter('mode', '') == 'upgrade') && $this->oWizard->GetParameter('db_backup', false) && $this->oWizard->GetParameter('authent', false)) { - $sBackupDestination = $this->oWizard->GetParameter('db_backup_path', ''); - if (file_exists($sBackupDestination.'.tar.gz')) { - $bHasBackup = true; - // To mitigate security risks: pass only the filename without the extension, the download will add the extension itself - $oPage->p('Your backup is ready'); - $oPage->p(' Download '.basename($sBackupDestination).''); - } else { - $oPage->p(' Warning: Backup creation failed !'); - } - } - - // Form goes here.. No back button since the job is done ! - $oPage->add(''); - - $oPage->add('
    '); - - $oConfig = new Config(utils::GetConfigFilePath()); - $aParamValues = $this->oWizard->GetParamForConfigArray(); - $oConfig->UpdateFromParams($aParamValues); - // Load the data model only, in order to load env-production/core/main.php to get the XML parameters (needed by GetModuleSettings below) - // But main.php may also contain classes (defined without any module), and thus requiring the full data model - // to be loaded to prevent "class not found" errors... - $oProductionEnv = new RunTimeEnvironment('production'); - $oProductionEnv->InitDataModel($oConfig, true); - $sIframeUrl = $oConfig->GetModuleSetting('itop-hub-connector', 'setup_url', ''); - - $sSetupTokenFile = APPROOT.'data/.setup'; - $sSetupToken = bin2hex(random_bytes(12)); - file_put_contents($sSetupTokenFile, $sSetupToken); - $sIframeUrl .= "&setup_token=$sSetupToken"; - - if ($sIframeUrl != '') { - $oPage->add(''); - - $oPage->add_script(" - window.addEventListener('message', function(event) { - if (event.data === 'itophub_load_completed') - { - $('#placeholder').hide(); - $('#fresh_content').show(); - } - }, false); - "); - } - - $sForm = '
    '; - $sForm .= ''; - $sForm .= ''; - $sForm .= "
    "; - $sForm .= ''; - - $sForm = addslashes($sForm); - $oPage->add_ready_script("$('#wiz_form').append('$sForm');"); - // avoid leaving in a dirty state - SetupUtils::ExitMaintenanceMode(false); - SetupUtils::ExitReadOnlyMode(false); - - if (false === $bHasBackup) { - SetupUtils::EraseSetupToken(); - } - } - - public function CanMoveForward() - { - return false; - } - public function CanMoveBackward() - { - return false; - } - - /** - * Tells whether this step of the wizard requires that the configuration file be writable - * @return bool True if the wizard will possibly need to modify the configuration at some point - */ - public function RequiresWritableConfig() - { - return false; //This step executes once the config was written and secured - } - - public function AsyncAction(WebPage $oPage, $sCode, $aParameters) - { - SetupUtils::EraseSetupToken(); - // For security reasons: add the extension now so that this action can be used to read *only* .tar.gz files from the disk... - $sBackupFile = $aParameters['backup'].'.tar.gz'; - if (file_exists($sBackupFile)) { - // Make sure there is NO output at all before our content, otherwise the document will be corrupted - $sPreviousContent = ob_get_clean(); - $oPage->SetContentType('application/gzip'); - $oPage->SetContentDisposition('attachment', basename($sBackupFile)); - $oPage->add(file_get_contents($sBackupFile)); - } - } -} diff --git a/setup/wizardsteps/AbstractWizStepInstall.php b/setup/wizardsteps/AbstractWizStepInstall.php new file mode 100644 index 0000000000..60f39a6c1d --- /dev/null +++ b/setup/wizardsteps/AbstractWizStepInstall.php @@ -0,0 +1,118 @@ +oWizard->GetParameter('install_mode', 'install'); + $aSelectedModules = json_decode($this->oWizard->GetParameter('selected_modules'), true); + $aSelectedExtensions = json_decode($this->oWizard->GetParameter('selected_extensions'), true); + $sBackupDestination = ''; + $sPreviousConfigurationFile = ''; + $bCopySetupFiles = $this->oWizard->GetParameter('copy_setup_files', true); + $sDBName = $this->oWizard->GetParameter('db_name'); + if ($sMode == 'upgrade') { + $sPreviousVersionDir = $this->oWizard->GetParameter('previous_version_dir', ''); + if (!empty($sPreviousVersionDir)) { + $aPreviousInstance = SetupUtils::GetPreviousInstance($sPreviousVersionDir); + if ($aPreviousInstance['found']) { + $sPreviousConfigurationFile = $aPreviousInstance['configuration_file']; + } + } + + if ($this->oWizard->GetParameter('db_backup', false)) { + $sBackupDestination = $this->oWizard->GetParameter('db_backup_path', ''); + } + } else { + $sDBNewName = $this->oWizard->GetParameter('db_new_name', ''); + if ($sDBNewName != '') { + $sDBName = $sDBNewName; // Database will be created + } + } + + $sSourceDir = $this->oWizard->GetParameter('source_dir'); + if (($sMode == 'upgrade') && ($this->oWizard->GetParameter('upgrade_type') == 'keep-previous')) { + //$sPreviousVersionDir = $this->oWizard->GetParameter('previous_version_dir'); + //$aCopies[] = ['source' => $sSourceDir, 'destination' => 'modules']; // Source is an absolute path, destination is relative to APPROOT + //$aCopies[] = ['source' => $sPreviousVersionDir.'/portal', 'destination' => 'portal']; // Source is an absolute path, destination is relative to APPROOT + $sSourceDir = APPROOT.'modules'; + } + + $aInstallParams = [ + 'mode' => $sMode, + 'optional_steps' => [ + 'log-parameters' => true, + 'migrate-before' => true, + 'migrate-after' => true, + 'setup-audit' => true, + // 'backup' => see below + ], + 'source_dir' => str_replace(APPROOT, '', $sSourceDir), + 'datamodel_version' => $this->oWizard->GetParameter('datamodel_version'), //TODO: let the installer compute this automatically... + 'previous_configuration_file' => $sPreviousConfigurationFile, + 'extensions_dir' => $this->oWizard->GetParameter('extensions_dir', 'extensions'), + 'target_env' => 'production', + 'workspace_dir' => '', + 'database' => [ + 'server' => $this->oWizard->GetParameter('db_server'), + 'user' => $this->oWizard->GetParameter('db_user'), + 'pwd' => $this->oWizard->GetParameter('db_pwd'), + 'name' => $sDBName, + 'db_tls_enabled' => $this->oWizard->GetParameter('db_tls_enabled'), + 'db_tls_ca' => $this->oWizard->GetParameter('db_tls_ca'), + 'prefix' => $this->oWizard->GetParameter('db_prefix'), + ], + 'url' => $this->oWizard->GetParameter('application_url'), + 'graphviz_path' => $this->oWizard->GetParameter('graphviz_path'), + 'admin_account' => [ + 'user' => $this->oWizard->GetParameter('admin_user'), + 'pwd' => $this->oWizard->GetParameter('admin_pwd'), + 'language' => $this->oWizard->GetParameter('admin_language'), + ], + 'language' => $this->oWizard->GetParameter('default_language'), + 'selected_modules' => $aSelectedModules, + 'selected_extensions' => $aSelectedExtensions, + 'sample_data' => $this->oWizard->GetParameter('sample_data', '') === 'yes', + 'old_addon' => $this->oWizard->GetParameter('old_addon', false), // whether or not to use the "old" userrights profile addon + 'options' => json_decode($this->oWizard->GetParameter('misc_options', '[]'), true), + 'mysql_bindir' => $this->oWizard->GetParameter('mysql_bindir'), + 'use_symbolic_links' => $this->oWizard->GetParameter('use_symbolic_links', MFCompiler::UseSymbolicLinks()), + ]; + + if ($sBackupDestination != '') { + $aInstallParams['optional_steps']['backup'] = [ + 'destination' => $sBackupDestination, + 'configuration_file' => $sPreviousConfigurationFile, + ]; + } + + if ($bCopySetupFiles) { + $aInstallParams['optional_steps']['copy'] = true; + } + + return $aInstallParams; + } + +} diff --git a/setup/wizardsteps/AbstractWizStepMiscParams.php b/setup/wizardsteps/AbstractWizStepMiscParams.php new file mode 100644 index 0000000000..5662bf500b --- /dev/null +++ b/setup/wizardsteps/AbstractWizStepMiscParams.php @@ -0,0 +1,80 @@ +oWizard->GetParameter('use_symbolic_links', MFCompiler::UseSymbolicLinks()) ? ' checked ' : ''; + + $oPage->add('
    '); + $oPage->add('Dev parameters'); + $oPage->p('
    '); + } + } + + final protected function AddForceUninstallFlagOption(WebPage $oPage): void + { + $sChecked = $this->oWizard->GetParameter('force-uninstall', false) ? ' checked ' : ''; + $oPage->add('
    '); + + $oPage->add('
    '); + $oPage->add(''); + $oPage->add('
    '); + $oPage->add(''); + $oPage->add('
    This could result in data corruption and application crashes.
    '); + $oPage->add('
    '); + $oPage->add('
    '); + $oPage->add('
    '); + $oPage->add_style( + <<add_ready_script( + <<<'JS' +$("[data-role=\"setup-collapsable-options--toggler\"").on('click', function() { + var $tbody = $(this).closest("div"); + $tbody.children().not(":first-child").toggle(); + $tbody.toggleClass('setup-is-opened'); +}); +$("#force-uninstall").on("click", function() { + let $this = $(this); + let bForceUninstall = $this.prop("checked"); + if( bForceUninstall && !confirm('Beware, uninstalling extensions flagged as non uninstallable may result in data corruption and application crashes. Are you sure you want to continue ?')){ + $this.prop("checked",false); + } +}); +JS + ); + } +} diff --git a/setup/wizardsteps/WizStepAdminAccount.php b/setup/wizardsteps/WizStepAdminAccount.php new file mode 100644 index 0000000000..57572a2911 --- /dev/null +++ b/setup/wizardsteps/WizStepAdminAccount.php @@ -0,0 +1,109 @@ +oWizard->SaveParameter('admin_user', ''); + $this->oWizard->SaveParameter('admin_pwd', ''); + $this->oWizard->SaveParameter('confirm_pwd', ''); + $this->oWizard->SaveParameter('admin_language', 'EN US'); + + return new WizardState(WizStepInstallMiscParams::class); + } + + public function Display(SetupPage $oPage): void + { + $sAdminUser = $this->oWizard->GetParameter('admin_user', 'admin'); + $sAdminPwd = $this->oWizard->GetParameter('admin_pwd', ''); + $sConfirmPwd = $this->oWizard->GetParameter('confirm_pwd', ''); + $sAdminLanguage = $this->oWizard->GetParameter('admin_language', 'EN US'); + $oPage->add('

    Definition of the Administrator Account

    '); + $oPage->add('
    '); + $oPage->add('Administrator Account'); + $oPage->add(''); + $oPage->add(''); + $oPage->add(''); + $oPage->add(''); + $sSourceDir = APPROOT.'dictionaries/'; + $aLanguages = SetupUtils::GetAvailableLanguages($sSourceDir); + $oPage->add(''); + $oPage->add('
    Login:
    Password:
    Confirm password:
    Language: '); + $oPage->add(SetupUtils::GetLanguageSelect($sSourceDir, 'admin_language', $sAdminLanguage)); + $oPage->add('
    '); + $oPage->add('
    '); + $oPage->add_ready_script( + <<'); + } + else + { + $("#v_admin_user").html(''); + } + + bPasswordsMatch = ($('#admin_pwd').val() == $('#confirm_pwd').val()); + if (!bPasswordsMatch) + { + $('#v_admin_pwd').html(''); + } + else + { + $('#v_admin_pwd').html(''); + } + bRet = bPasswordsMatch && bRet; + + return bRet; +EOF + ; + } +} diff --git a/setup/wizardsteps/WizStepDBParams.php b/setup/wizardsteps/WizStepDBParams.php new file mode 100644 index 0000000000..f8d870680e --- /dev/null +++ b/setup/wizardsteps/WizStepDBParams.php @@ -0,0 +1,118 @@ +oWizard->SaveParameter('db_server', ''); + $this->oWizard->SaveParameter('db_user', ''); + $this->oWizard->SaveParameter('db_pwd', ''); + $this->oWizard->SaveParameter('db_name', ''); + $this->oWizard->SaveParameter('db_prefix', ''); + $this->oWizard->SaveParameter('new_db_name', ''); + $this->oWizard->SaveParameter('create_db', ''); + $this->oWizard->SaveParameter('db_new_name', ''); + $this->oWizard->SaveParameter('db_tls_enabled', false); + $this->oWizard->SaveParameter('db_tls_ca', ''); + + return new WizardState(WizStepAdminAccount::class); + } + + public function Display(SetupPage $oPage): void + { + $oPage->add('

    Configuration of the database connection:

    '); + $sDBServer = $this->oWizard->GetParameter('db_server', ''); + $sDBUser = $this->oWizard->GetParameter('db_user', ''); + $sDBPwd = $this->oWizard->GetParameter('db_pwd', ''); + $sDBName = $this->oWizard->GetParameter('db_name', ''); + $sDBPrefix = $this->oWizard->GetParameter('db_prefix', ''); + $sTlsEnabled = $this->oWizard->GetParameter('db_tls_enabled', ''); + $sTlsCA = $this->oWizard->GetParameter('db_tls_ca', ''); + $sNewDBName = $this->oWizard->GetParameter('db_new_name', false); + + $oPage->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') { + $oPage->add_ready_script('$("#existing_db").prop("checked", true);'); + } else { + $oPage->add_ready_script('$("#create_db").prop("checked", true);'); + } + } + + public function AsyncAction(WebPage $oPage, $sCode, $aParameters) + { + switch ($sCode) { + case 'check_db': + SetupUtils::AsyncCheckDB($oPage, $aParameters); + break; + } + } + + /** + * Tells whether the "Next" button should be enabled interactively + * @return string A piece of javascript code returning either true or false + */ + public function JSCanMoveForward() + { + return + <<CheckDependencies()) { + return true; + } else { + return false; + } + } + + public function UpdateWizardStateAndGetNextStep($bMoveForward = true): WizardState + { + return new WizardState(WizStepSummary::class); + } + + public function CanComeBack() + { + return false; + } + + public function Display(SetupPage $oPage): void + { + + $aInstallParams = $this->BuildConfig(); + + $this->AddProgressBar($oPage, 'Progress of the verification'); + + $sJSONData = json_encode($aInstallParams); + $oPage->add(''); + + $sAuthentToken = $this->oWizard->GetParameter('authent', ''); + $oPage->add(''); + if (!$this->CheckDependencies()) { + $oPage->error($this->sDependencyIssue); + $oPage->add_ready_script(<<add_ready_script(<< '[]', + 'selected_extensions' => '[]', + 'display_choices' => '[]', + 'added_extensions' => '[]', + 'removed_extensions' => '[]', + 'extensions_not_uninstallable' => '[]', + 'copy_setup_files' => 1, + ]; + $aHiddenInputs = ''; + foreach ($aParams as $sParamName => $defaultValue) { + $sElements = utils::HtmlEntities($this->oWizard->GetParameter($sParamName, $defaultValue)); + $sParamName = utils::HtmlEntities($sParamName); + $aHiddenInputs .= << +INPUT; + } + + $sUID = Session::Get('setup_token'); + $oPage->add( + << + + + $aHiddenInputs + +HTML + ); + } + + protected function AddProgressErrorScript($oPage, $aRes) + { + if (isset($aRes['error_code']) && $aRes['error_code'] === DataAuditSequencer::DATA_AUDIT_FAILED) { + $oPage->add_ready_script( + <<'); + $('#ignore_and_continue').on('click', function() { + return confirm("If you skip the cleanup you won't be able to run the process later. You'll have to migrate or delete unconsistent data manually."); + }); + $('.ibo-setup--wizard--buttons-container tr td:nth-child(2)').after(' '); + $('#goto-data-feature-removal').on("click", function() { + $('#goto-data-feature-removal').prop('disabled', true); + $('#submit-wait').removeClass("ibo-is-hidden"); + $('#data-feature-removal').submit(); + }); + + $("#wiz_form").data("installation_status", "cleanup_needed"); + $('#btn_next').hide(); +EOF + ); + } + + } + + public function JSCanMoveForward() + { + return 'return ["completed", "cleanup_needed"].indexOf($("#wiz_form").data("installation_status")) !== -1;'; + } + + public function JSCanMoveBackward() + { + return 'return ["not started", "error", "cleanup_needed"].indexOf($("#wiz_form").data("installation_status")) !== -1;'; + } +} diff --git a/setup/wizardsteps/WizStepDetectedInfo.php b/setup/wizardsteps/WizStepDetectedInfo.php new file mode 100644 index 0000000000..f2b0a0aca0 --- /dev/null +++ b/setup/wizardsteps/WizStepDetectedInfo.php @@ -0,0 +1,258 @@ +oWizard->SetParameter('mode', 'upgrade'); + $this->oWizard->SetParameter('upgrade_type', $sUpgradeType); + $bDisplayLicense = $this->oWizard->GetParameter('display_license'); + + switch ($sUpgradeType) { + case 'keep-previous': + $sSourceDir = utils::ReadParam('relative_source_dir', '', false, 'raw_data'); + $this->oWizard->SetParameter('source_dir', $this->oWizard->GetParameter('previous_version_dir').'/'.$sSourceDir); + $this->oWizard->SetParameter('datamodel_version', utils::ReadParam('datamodel_previous_version', '', false, 'raw_data')); + break; + + case 'use-compatible': + $sDataModelPath = utils::ReadParam('datamodel_path', '', false, 'raw_data'); + $this->oWizard->SetParameter('source_dir', $sDataModelPath); + $this->oWizard->SaveParameter('datamodel_version', ''); + break; + + default: + // Do nothing, maybe the user pressed the Back button + } + if ($bDisplayLicense) { + $aRet = new WizardState(WizStepLicense2::class); + } else { + $aRet = new WizardState(WizStepUpgradeMiscParams::class); + } + return $aRet; + } + + /** + * @param \SetupPage $oPage + * + * @throws Exception + */ + public function Display(SetupPage $oPage): void + { + $oPage->add_style( + <<bCanMoveForward = true; + $bDisplayLicense = true; + $sPreviousVersionDir = $this->oWizard->GetParameter('previous_version_dir', ''); + $aInstalledInfo = SetupUtils::GetApplicationVersion($this->oWizard); + + if ($aInstalledInfo === false) { + throw(new Exception('No previous version of '.ITOP_APPLICATION.' found in the supplied database. The upgrade cannot continue.')); + } elseif (strcasecmp($aInstalledInfo['product_name'], ITOP_APPLICATION) != 0) { + $oPage->p("Warning: The installed products seem different. Are you sure that you want to upgrade {$aInstalledInfo['product_name']} with ".ITOP_APPLICATION."?"); + } + + $sInstalledVersion = $aInstalledInfo['product_version']; + $sInstalledDataModelVersion = $aInstalledInfo['datamodel_version']; + + $oPage->add("

    Information about the upgrade from version $sInstalledVersion to ".ITOP_VERSION_FULL."

    "); + + if ($sInstalledVersion == ITOP_VERSION_FULL) { + // Reinstalling the same version let's skip the license agreement... + $bDisplayLicense = false; + } + $this->oWizard->SetParameter('display_license', $bDisplayLicense); // Remember for later + + $sCompatibleDMDir = SetupUtils::GetLatestDataModelDir(); + if ($sCompatibleDMDir === false) { + // No compatible version exists... cannot upgrade. Either it is too old, or too new (downgrade !) + $this->bCanMoveForward = false; + $oPage->p("No datamodel directory found."); + } else { + $sUpgradeDMVersion = SetupUtils::GetDataModelVersion($sCompatibleDMDir); + $sPreviousSourceDir = isset($aInstalledInfo['source_dir']) ? $aInstalledInfo['source_dir'] : 'modules'; + $aChanges = false; + if (is_dir($sPreviousVersionDir)) { + // Check if the previous version is a "genuine" one or not... + $aChanges = SetupUtils::CheckVersion($sInstalledDataModelVersion, $sPreviousVersionDir.'/'.$sPreviousSourceDir); + } + if (($aChanges !== false) && ((count($aChanges['added']) > 0) || (count($aChanges['removed']) > 0) || (count($aChanges['modified']) > 0))) { + // Some changes were detected, prompt the user to keep or discard them + $oPage->p(" Some modifications were detected between the ".ITOP_APPLICATION." version in '$sPreviousVersionDir' and a genuine $sInstalledVersion version."); + $oPage->p("What do you want to do?"); + + $aWritableDirs = ['modules', 'portal']; + $aErrors = SetupUtils::CheckWritableDirs($aWritableDirs); + $sChecked = ($this->oWizard->GetParameter('upgrade_type') == 'keep-previous') ? ' checked ' : ''; + $sDisabled = (count($aErrors) > 0) ? ' disabled ' : ''; + + $oPage->p(''); + $oPage->add(''); + + $oPage->add(''); + + if (count($aErrors) > 0) { + $oPage->p("Cannot copy the installed version due to the following access rights issue(s):"); + foreach ($aErrors as $sDir => $oCheckResult) { + $oPage->p(' '.$oCheckResult->sLabel); + } + } + + $sChecked = ($this->oWizard->GetParameter('upgrade_type') == 'use-compatible') ? ' checked ' : ''; + + $oPage->p(''); + + $oPage->add(''); + $oPage->add(''); + + $oPage->add('
    Details of the modifications
    '); + if (count($aChanges['added']) > 0) { + $oPage->add('
      New files added:'); + foreach ($aChanges['added'] as $sFilePath => $void) { + $oPage->add('
    • '.$sFilePath.'
    • '); + } + $oPage->add('
    '); + } + if (count($aChanges['removed']) > 0) { + $oPage->add('
      Deleted files:'); + foreach ($aChanges['removed'] as $sFilePath => $void) { + $oPage->add('
    • '.$sFilePath.'
    • '); + } + $oPage->add('
    '); + } + if (count($aChanges['modified']) > 0) { + $oPage->add('
      Modified files:'); + foreach ($aChanges['modified'] as $sFilePath => $void) { + $oPage->add('
    • '.$sFilePath.'
    • '); + } + $oPage->add('
    '); + } + $oPage->add('
    '); + } else { + // No changes detected... or no way to tell because of the lack of a manifest or previous source dir + // Use the "compatible" datamodel as-is. + $sCompatibleDMDirToDisplay = utils::HtmlEntities($sCompatibleDMDir); + $sUpgradeDMVersionToDisplay = utils::HtmlEntities($sUpgradeDMVersion); + $oPage->add( + <<The datamodel will be upgraded from version $sInstalledDataModelVersion to version $sUpgradeDMVersion. + + + +HTML + ); + + } + + $oPage->add_ready_script( + <<oWizard->GetParameter('db_name', '').$this->oWizard->GetParameter('db_prefix', ''), + $this->oWizard->GetParameter('db_server', ''), + $this->oWizard->GetParameter('db_user', ''), + $this->oWizard->GetParameter('db_pwd', ''), + $this->oWizard->GetParameter('db_tls_enabled', ''), + $this->oWizard->GetParameter('db_tls_ca', '') + ); + if ($oMutex->IsLocked()) { + $oPage->add('
    '.ITOP_APPLICATION.' cron process is being executed on the target database. '.ITOP_APPLICATION.' cron process will be stopped during the setup execution.
    '); + } + } + } + + public function CanMoveForward() + { + return $this->bCanMoveForward; + } + + /** + * Tells whether the "Next" button should be enabled interactively + * @return string A piece of javascript code returning either true or false + */ + public function JSCanMoveForward() + { + return + << 0); + return bRet; +EOF + ; + } +} diff --git a/setup/wizardsteps/WizStepDone.php b/setup/wizardsteps/WizStepDone.php new file mode 100644 index 0000000000..2cde077c26 --- /dev/null +++ b/setup/wizardsteps/WizStepDone.php @@ -0,0 +1,169 @@ +oWizard); + + $sRootUrl = utils::GetAbsoluteUrlAppRoot(true); + $aSelectedModules = json_decode($this->oWizard->GetParameter('selected_modules'), true); + foreach ($aSelectedModules as $sModuleId) { + if (!empty($aAvailableModules[$sModuleId]['doc.manual_setup'])) { + $sUrl = $aAvailableModules[$sModuleId]['doc.manual_setup']; + $sManualStepUrl = utils::IsURL($sUrl) ? $sUrl : $sRootUrl.$sUrl; + $aManualSteps[$aAvailableModules[$sModuleId]['label']] = $sManualStepUrl; + } + } + $oPage->add('
    '); + if (count($aManualSteps) > 0) { + $oPage->add("

    Manual operations required

    "); + $oPage->p("In order to complete the installation, the following manual operations are required:"); + foreach ($aManualSteps as $sModuleLabel => $sUrl) { + $oPage->p("Manual instructions for $sModuleLabel"); + } + $oPage->add("

    Congratulations for installing ".ITOP_APPLICATION."

    "); + } else { + $oPage->add("

    Congratulations for installing ".ITOP_APPLICATION."

    "); + $oPage->ok("The installation completed successfully."); + } + + $bHasBackup = false; + if (($this->oWizard->GetParameter('mode', '') == 'upgrade') && $this->oWizard->GetParameter('db_backup', false) && $this->oWizard->GetParameter('authent', false)) { + $sBackupDestination = $this->oWizard->GetParameter('db_backup_path', ''); + if (file_exists($sBackupDestination.'.tar.gz')) { + $bHasBackup = true; + // To mitigate security risks: pass only the filename without the extension, the download will add the extension itself + $oPage->p('Your backup is ready'); + $oPage->p(' Download '.basename($sBackupDestination).''); + } else { + $oPage->p(' Warning: Backup creation failed !'); + } + } + + // Form goes here.. No back button since the job is done ! + $oPage->add(''); + + $oPage->add('
    '); + + $oConfig = new Config(utils::GetConfigFilePath()); + $aParamValues = $this->oWizard->GetParamForConfigArray(); + $oConfig->UpdateFromParams($aParamValues); + // Load the data model only, in order to load env-production/core/main.php to get the XML parameters (needed by GetModuleSettings below) + // But main.php may also contain classes (defined without any module), and thus requiring the full data model + // to be loaded to prevent "class not found" errors... + $oProductionEnv = new RunTimeEnvironment(ITOP_DEFAULT_ENV); + $oProductionEnv->InitDataModel($oConfig, true); + $sIframeUrl = $oConfig->GetModuleSetting('itop-hub-connector', 'setup_url', ''); + + $sSetupTokenFile = APPROOT.'data/.setup'; + $sSetupToken = bin2hex(random_bytes(12)); + file_put_contents($sSetupTokenFile, $sSetupToken); + + if (mb_strlen($sIframeUrl) > 0) { + $sIframeUrl .= "&setup_token=$sSetupToken"; + $oPage->add(''); + + $oPage->add_script(" + window.addEventListener('message', function(event) { + if (event.data === 'itophub_load_completed') + { + $('#placeholder').hide(); + $('#fresh_content').show(); + } + }, false); + "); + } + + $sForm = '
    '; + $sForm .= ''; + $sForm .= ''; + $sForm .= "
    "; + $sForm .= ''; + + $sForm = addslashes($sForm); + $oPage->add_ready_script("$('#wiz_form').append('$sForm');"); + // avoid leaving in a dirty state + SetupUtils::ExitMaintenanceMode(false); + SetupUtils::ExitReadOnlyMode(false); + + if (false === $bHasBackup) { + SetupUtils::EraseSetupToken(); + } + } + + public function CanMoveForward() + { + return false; + } + public function CanMoveBackward() + { + return false; + } + + /** + * Tells whether this step of the wizard requires that the configuration file be writable + * @return bool True if the wizard will possibly need to modify the configuration at some point + */ + public function RequiresWritableConfig() + { + return false; //This step executes once the config was written and secured + } + + public function AsyncAction(WebPage $oPage, $sCode, $aParameters) + { + SetupUtils::EraseSetupToken(); + // For security reasons: add the extension now so that this action can be used to read *only* .tar.gz files from the disk... + $sBackupFile = $aParameters['backup'].'.tar.gz'; + if (file_exists($sBackupFile)) { + // Make sure there is NO output at all before our content, otherwise the document will be corrupted + $sPreviousContent = ob_get_clean(); + $oPage->SetContentType('application/gzip'); + $oPage->SetContentDisposition('attachment', basename($sBackupFile)); + $oPage->add(file_get_contents($sBackupFile)); + } + } +} diff --git a/setup/wizardsteps/WizStepInstall.php b/setup/wizardsteps/WizStepInstall.php new file mode 100644 index 0000000000..9b3499acc7 --- /dev/null +++ b/setup/wizardsteps/WizStepInstall.php @@ -0,0 +1,190 @@ +> " button + * @return string The label for the button + */ + public function GetNextButtonLabel() + { + return 'Continue'; + } + + public function CanMoveForward() + { + if ($this->CheckDependencies()) { + return true; + } else { + return false; + } + } + + public function UpdateWizardStateAndGetNextStep($bMoveForward = true): WizardState + { + return new WizardState(WizStepDone::class); + } + + protected function AddProgressBar(WebPage $oPage, string $sTitle = 'Progress of the operations') + { + $oPage->add('
    '.$sTitle.''); + $oPage->add('
    '); + $oPage->LinkScriptFromAppRoot('setup/jquery.progression.js'); + $oPage->add('

    Ready to start...

    0%
    '); + $oPage->add('
    '); // progress_content + $oPage->add('
    '); + $oPage->add("
    "); + } + + protected function AddPrevStepSuccessMessage(WebPage $oPage, string $sPrevStepSuccessMessage): void + { + if ($sPrevStepSuccessMessage === '') { + return; + } + + $sPrevStepSuccessMessage = addslashes(utils::EscapeHtml($sPrevStepSuccessMessage)); + $oPage->add_ready_script( + <<').html('$sPrevStepSuccessMessage').appendTo("#progress_content"); +EOF + ); + } + + public function Display(SetupPage $oPage): void + { + $aInstallParams = $this->BuildConfig(); + $this->AddProgressBar($oPage, 'Progress of the installation'); + + $sJSONData = json_encode($aInstallParams); + $oPage->add(''); + + $sAuthentToken = $this->oWizard->GetParameter('authent', ''); + $oPage->add(''); + if (!$this->CheckDependencies()) { + $oPage->error($this->sDependencyIssue); + $oPage->add_ready_script(<<add_ready_script(<<LoadFromHash(json_decode($sJSONParameters, true /* bAssoc */)); + /** @var StepSequencer $oInstaller */ + $oInstaller = new (static::SequencerClass)($oParameters); + $aRes = $oInstaller->ExecuteStep($sStep); + if (($aRes['status'] !== StepSequencer::ERROR) && ($aRes['next-step'] != '')) { + // Tell the web page to move the progress bar and to launch the next step + $sMessage = addslashes(utils::EscapeHtml($aRes['next-step-label'])); + $oPage->add_ready_script( + <<{$aRes['next-step-label']}'); + ExecuteStep('{$aRes['next-step']}'); +EOF + ); + static::AddPrevStepSuccessMessage($oPage, $aRes['prev-step-success-message']); + } elseif ($aRes['status'] !== StepSequencer::ERROR) { + // Installation complete, move to the next step of the wizard + $oPage->add_ready_script( + <<', $sMessage); + $oPage->add_ready_script( + <<AddProgressErrorScript($oPage, $aRes); + } + } + + protected function AddProgressErrorScript($oPage, $aRes) + { + + } + + /** + * Tells whether the "Next" button should be enabled interactively + * @return string A piece of javascript code returning either true or false + */ + public function JSCanMoveForward() + { + return 'return $("#wiz_form").data("installation_status") === "completed";'; + } + + /** + * Tells whether the "Next" button should be enabled interactively + * @return string A piece of javascript code returning either true or false + */ + public function JSCanMoveBackward() + { + return 'var sStatus = $("#wiz_form").data("installation_status"); return ((sStatus === "not started") || (sStatus === "error"));'; + } + +} diff --git a/setup/wizardsteps/WizStepInstallMiscParams.php b/setup/wizardsteps/WizStepInstallMiscParams.php new file mode 100644 index 0000000000..1bc5321070 --- /dev/null +++ b/setup/wizardsteps/WizStepInstallMiscParams.php @@ -0,0 +1,185 @@ +oWizard->SaveParameter('default_language', ''); + $this->oWizard->SaveParameter('application_url', ''); + $this->oWizard->SaveParameter('graphviz_path', ''); + $this->oWizard->SaveParameter('sample_data', 'yes'); + $this->oWizard->SaveParameter('use_symbolic_links', false); + return new WizardState(WizStepModulesChoice::class, 'start_install'); + } + + public function Display(SetupPage $oPage): void + { + $sDefaultLanguage = $this->oWizard->GetParameter('default_language', $this->oWizard->GetParameter('admin_language')); + $sApplicationURL = $this->oWizard->GetParameter('application_url', utils::GetDefaultUrlAppRoot(true)); + $sDefaultGraphvizPath = (strtolower(substr(PHP_OS, 0, 3)) === 'win') ? 'C:\\Program Files\\Graphviz\\bin\\dot.exe' : '/usr/bin/dot'; + $sGraphvizPath = $this->oWizard->GetParameter('graphviz_path', $sDefaultGraphvizPath); + $sSampleData = $this->oWizard->GetParameter('sample_data', 'yes'); + $oPage->add('

    Additional parameters

    '); + $oPage->add('
    '); + $oPage->add('Default Language'); + $oPage->add(''); + $sSourceDir = APPROOT.'dictionaries/'; + $aLanguages = SetupUtils::GetAvailableLanguages($sSourceDir); + $oPage->add(''); + $oPage->add('
    Default Language: '); + $oPage->add(SetupUtils::GetLanguageSelect($sSourceDir, 'default_language', $sDefaultLanguage)); + $oPage->add('
    '); + $oPage->add('
    '); + $oPage->add('
    '); + $oPage->add('Application URL'); + $oPage->add(''); + $oPage->add(''); + $oPage->add('
    URL:
    '); + $oPage->add('
    Change the value above if the end-users will be accessing the application by another path due to a specific configuration of the web server.
    '); + $oPage->add('
    '); + $oPage->add('
    '); + $oPage->add('Path to Graphviz\' dot application'); + $oPage->add(''); + $oPage->add(''); + $oPage->add(''); + $oPage->add('
    Path:
    '); + $oPage->add(''); + $oPage->add('
    '); + $oPage->add('
    '); + $oPage->add('Sample Data'); + $sChecked = ($sSampleData == 'yes') ? 'checked ' : ''; + $oPage->p('
    '); + $sAuthentToken = $this->oWizard->GetParameter('authent', ''); + $oPage->add(''); + $oPage->add_ready_script( + <<AddUseSymlinksFlagOption($oPage); + } + + public function AsyncAction(WebPage $oPage, $sCode, $aParameters) + { + switch ($sCode) { + case 'check_graphviz': + $sGraphvizPath = $aParameters['graphviz_path']; + $aCheck = SetupUtils::CheckGraphviz($sGraphvizPath); + + // N°2214 logging TRACE results + $aTraceCheck = CheckResult::FilterCheckResultArray($aCheck, [CheckResult::TRACE]); + foreach ($aTraceCheck as $oTraceCheck) { + SetupLog::Ok($oTraceCheck->sLabel); + } + + $aNonTraceCheck = array_diff($aCheck, $aTraceCheck); + foreach ($aNonTraceCheck as $oCheck) { + switch ($oCheck->iSeverity) { + case CheckResult::INFO: + $sStatus = 'ok'; + $sInfoExplanation = $oCheck->sLabel; + $sMessage = json_encode('
    '.$sInfoExplanation.'
    '); + + break; + + default: + case CheckResult::ERROR: + case CheckResult::WARNING: + $sStatus = 'ko'; + $sErrorExplanation = $oCheck->sLabel; + $sMessage = json_encode('
    '.$sErrorExplanation.'
    '); + break; + } + + if ($oCheck->iSeverity !== CheckResult::TRACE) { + $oPage->add_ready_script( + <<'); + } + else + { + $("#v_application_url").html(''); + } + bGraphviz = ($('#graphviz_path').val() != ''); + if (!bGraphviz) + { + // Does not prevent to move forward + $("#v_graphviz_path").html(''); + } + else + { + $("#v_graphviz_path").html(''); + } + return bRet; +EOF + ; + } +} diff --git a/setup/wizardsteps/WizStepInstallOrUpgrade.php b/setup/wizardsteps/WizStepInstallOrUpgrade.php new file mode 100644 index 0000000000..fc7cccf642 --- /dev/null +++ b/setup/wizardsteps/WizStepInstallOrUpgrade.php @@ -0,0 +1,217 @@ +oWizard->SaveParameter('previous_version_dir', ''); + $this->oWizard->SaveParameter('db_server', ''); + $this->oWizard->SaveParameter('db_user', ''); + $this->oWizard->SaveParameter('db_pwd', ''); + $this->oWizard->SaveParameter('db_name', ''); + $this->oWizard->SaveParameter('db_prefix', ''); + $this->oWizard->SaveParameter('db_tls_enabled', false); + $this->oWizard->SaveParameter('db_tls_ca', ''); + + if ($sInstallMode == 'install') { + $this->oWizard->SetParameter('install_mode', 'install'); + $sFullSourceDir = SetupUtils::GetLatestDataModelDir(); + $this->oWizard->SetParameter('source_dir', $sFullSourceDir); + $this->oWizard->SetParameter('datamodel_version', SetupUtils::GetDataModelVersion($sFullSourceDir)); + $sNextStep = WizStepLicense::class; + } else { + $this->oWizard->SetParameter('install_mode', 'upgrade'); + $sNextStep = WizStepDetectedInfo::class; + + } + return new WizardState($sNextStep); + } + + public function Display(SetupPage $oPage): void + { + $sInstallMode = $this->oWizard->GetParameter('install_mode', ''); + $sDBServer = $this->oWizard->GetParameter('db_server', ''); + $sDBUser = $this->oWizard->GetParameter('db_user', ''); + $sDBPwd = $this->oWizard->GetParameter('db_pwd', ''); + $sDBName = $this->oWizard->GetParameter('db_name', ''); + $sDBPrefix = $this->oWizard->GetParameter('db_prefix', ''); + $sTlsEnabled = $this->oWizard->GetParameter('db_tls_enabled', false); + $sTlsCA = $this->oWizard->GetParameter('db_tls_ca', ''); + $sPreviousVersionDir = ''; + if ($sInstallMode == '') { + $aPreviousInstance = SetupUtils::GetPreviousInstance(APPROOT); + if ($aPreviousInstance['found']) { + $sInstallMode = 'upgrade'; + $sDBServer = $aPreviousInstance['db_server']; + $sDBUser = $aPreviousInstance['db_user']; + $sDBPwd = $aPreviousInstance['db_pwd']; + $sDBName = $aPreviousInstance['db_name']; + $sDBPrefix = $aPreviousInstance['db_prefix']; + $sTlsEnabled = $aPreviousInstance['db_tls_enabled']; + $sTlsCA = $aPreviousInstance['db_tls_ca']; + $this->oWizard->SaveParameter('graphviz_path', $aPreviousInstance['graphviz_path']); + $sPreviousVersionDir = APPROOT; + } else { + $sInstallMode = 'install'; + } + } + $sPreviousVersionDir = $this->oWizard->GetParameter('previous_version_dir', $sPreviousVersionDir); + + $sUpgradeInfoStyle = ''; + if ($sInstallMode == 'install') { + $sUpgradeInfoStyle = ' style="display: none;" '; + } + $oPage->add('
    What do you want to do?
    '); + $sChecked = ($sInstallMode == 'install') ? ' checked ' : ''; + $oPage->p(''); + $sChecked = ($sInstallMode == 'upgrade') ? ' checked ' : ''; + $sDisabled = (($sInstallMode == 'install') && (empty($sPreviousVersionDir))) ? ' disabled' : ''; + $oPage->p(''); + + $sUpgradeDir = utils::HtmlEntities($sPreviousVersionDir); + $oPage->add( + << +
    Location on the disk: +
    +HTML + ); + + SetupUtils::DisplayDBParameters( + $oPage, + false, + $sDBServer, + $sDBUser, + $sDBPwd, + $sDBName, + $sDBPrefix, + $sTlsEnabled, + $sTlsCA + ); + + $sAuthentToken = $this->oWizard->GetParameter('authent', ''); + $oPage->add(''); + $oPage->add(''); + //$oPage->add(''); + $oPage->add_ready_script( + <<add_ready_script( + <<add_ready_script( + <<add_ready_script( + <<GetBuildEnv().'/'.ITOP_CONFIG_FILE; + $this->oConfig = new Config($sBuildConfigFile); + + $oWizard->SetParameter('previous_version_dir', APPROOT); + $oWizard->SetParameter('install_mode', 'upgrade'); + $oWizard->SetParameter('source_dir', APPROOT.$this->oConfig->Get('source_dir')); + $oWizard->SetParameter('graphviz_path', $this->oConfig->Get('graphviz_path')); + $oWizard->SetParameter('application_url', $this->oConfig->Get('app_root_url')); + $oWizard->SetParameter('datamodel_version', ITOP_CORE_VERSION); + $oWizard->SetParameter('upgrade_type', 'use-compatible'); + + $oWizard->SaveParameter('use_symbolic_links', MFCompiler::UseSymbolicLinks()); + $oWizard->SaveParameter('force-uninstall', ''); + + // should be done at the end + parent::__construct($oWizard, $sCurrentState, false); + } + + /** + * @inheritDoc + */ + public function Display(SetupPage $oPage): void + { + } + + /** + * @inheritDoc + */ + public function UpdateWizardStateAndGetNextStep($bMoveForward = true): WizardState + { + $oProductionEnv = new RunTimeEnvironment(); + $sBuildConfigFile = APPCONF.$oProductionEnv->GetBuildEnv().'/'.ITOP_CONFIG_FILE; + @chmod($sBuildConfigFile, 0770); // In case it exists: RWX for owner and group, nothing for others + + $oConfig = new Config($sBuildConfigFile); + $this->oWizard->SetParameter('db_server', $oConfig->Get('db_host')); + $this->oWizard->SetParameter('db_user', $oConfig->Get('db_user')); + $this->oWizard->SetParameter('db_pwd', $oConfig->Get('db_pwd')); + $this->oWizard->SetParameter('db_name', $oConfig->Get('db_name')); + $this->oWizard->SetParameter('db_prefix', $oConfig->Get('db_subname')); + $this->oWizard->SetParameter('db_tls_enabled', $oConfig->Get('db_tls.enabled')); + $this->oWizard->SetParameter('db_tls_ca', $oConfig->Get('db_tls.ca') ?? ''); + + $this->oWizard->SetParameter('display_choices', '[]'); + $this->oWizard->SetParameter('extensions_not_uninstallable', '[]'); + + $aWizardSteps = $this->GetWizardSteps(); + $this->oWizard->SetWizardSteps($aWizardSteps); + $this->sCurrentState = count($aWizardSteps) - 1; + + $aSelectedComponents = $this->GetSelectedComponents($this->aSteps, $this->oWizard->GetParameter('selected_extensions')); + $this->oWizard->SetParameter('selected_components', json_encode($aSelectedComponents)); + + return new WizardState(WizStepDataAudit::class); + } + + /** + * @inheritDoc + */ + public function GetTitle(): string + { + return 'Before checking compatibility'; + } + + public function GetPossibleSteps() + { + return [WizStepDataAudit::class]; + } + + public function GetNextButtonLabel() + { + return 'Next'; + } + + public function CanComeBack() + { + return false; + } +} diff --git a/setup/wizardsteps/WizStepLicense.php b/setup/wizardsteps/WizStepLicense.php new file mode 100644 index 0000000000..73dce5df3b --- /dev/null +++ b/setup/wizardsteps/WizStepLicense.php @@ -0,0 +1,133 @@ +oWizard->SaveParameter('accept_license', 'no'); + return new WizardState(WizStepDBParams::class); + } + + /** + * @return bool true if we need to display a GDPR confirmation + * @throws \Exception + * @since 2.7.7 3.0.2 3.1.0 N°5037 method creation + * @since 2.7.8 3.0.3 3.1.0 N°5758 rename from NeedsRgpdConsent to NeedsGdprConsent + */ + private function NeedsGdprConsent() + { + $sMode = $this->oWizard->GetParameter('install_mode'); + + if ($sMode !== 'install') { + return false; + } + + $aModules = SetupUtils::AnalyzeInstallation($this->oWizard); + return SetupUtils::IsConnectableToITopHub($aModules); + } + + /** + * @param \SetupPage $oPage + */ + public function Display(SetupPage $oPage): void + { + $aLicenses = SetupUtils::GetLicenses(); + $oPage->add_style( + <<add('

    Licenses agreements for the components of '.ITOP_APPLICATION.'

    '); + $oPage->add_style('div a.no-arrow { background:transparent; padding-left:0;}'); + $oPage->add_style('.toggle { cursor:pointer; text-decoration:underline; color:#1C94C4; }'); + $oPage->add('
    '); + $oPage->add('Components of '.ITOP_APPLICATION.''); + $oPage->add('
      '); + $index = 0; + foreach ($aLicenses as $oLicense) { + $oPage->add('
    • '.$oLicense->product.', © '.$oLicense->author.' is licensed under the '.$oLicense->license_type.' license. (Details)'); + $oPage->add(''); + $oPage->add_ready_script('$(".license_text a").attr("target", "_blank").addClass("no-arrow");'); + $oPage->add_ready_script('$("#toggle_'.$index.'").on("click", function() { $("#license_'.$index.'").toggle(); } );'); + $index++; + } + $oPage->add('
    '); + $oPage->add('
    '); + $sChecked = ($this->oWizard->GetParameter('accept_license', 'no') == 'yes') ? ' checked ' : ''; + $oPage->add('
    '); + if ($this->NeedsGdprConsent()) { + $oPage->add('
    '); + $oPage->add('
    '); + $oPage->add('European General Data Protection Regulation'); + $oPage->add('
    '.ITOP_APPLICATION.' software is compliant with the processing of personal data according to the European General Data Protection Regulation (GDPR).

    +By installing '.ITOP_APPLICATION.' you agree that some information will be collected by Combodo to help you manage your instances and for statistical purposes. +This data remains anonymous until it is associated to a user account on iTop Hub.

    +

    List of collected data available in our Data privacy section.


    '); + $oPage->add(''); + $oPage->add(''); + $oPage->add('
    '); + } + $oPage->add_ready_script('$(".check_select").on("click change", function() { WizardUpdateButtons(); });'); + + $oPage->add_script( + <<bChoicesFromDatabase = false; + $this->oExtensionsMap = new iTopExtensionsMap(); + $sPreviousSourceDir = $this->oWizard->GetParameter('previous_version_dir', ''); + $sConfigPath = null; + if (($sPreviousSourceDir !== '') && is_readable($sPreviousSourceDir.'/conf/production/config-itop.php')) { + $sConfigPath = $sPreviousSourceDir.'/conf/production/config-itop.php'; + } elseif (is_readable(utils::GetConfigFilePath(ITOP_DEFAULT_ENV))) { + $sConfigPath = utils::GetConfigFilePath(ITOP_DEFAULT_ENV); + } + + // only called if the config file exists : we are updating a previous installation ! + // WARNING : we can't load this config directly, as it might be from another directory with a different approot_url (N°2684) + if ($sConfigPath !== null) { + $this->oConfig = new Config($sConfigPath); + + if ($bOverWriteConfig) { + $aParamValues = $oWizard->GetParamForConfigArray(); + $this->oConfig->UpdateFromParams($aParamValues); + } + + $this->oExtensionsMap->LoadChoicesFromDatabase($this->oConfig); + $this->bChoicesFromDatabase = true; + } + + // Sanity check (not stopper, to let developers go further...) + try { + $aModulesToLoad = json_decode($oWizard->GetParameter('selected_modules'), true) ?? null; + SetupLog::Error(__METHOD__, null, [$aModulesToLoad]); + $this->aAnalyzeInstallationModules = SetupUtils::AnalyzeInstallation($this->oWizard, true, $aModulesToLoad, $this->oConfig); + } catch (MissingDependencyException $e) { + $this->oMissingDependencyException = $e; + $this->aAnalyzeInstallationModules = SetupUtils::AnalyzeInstallation($this->oWizard); + } + } + + public function GetTitle(): string + { + $aStepInfo = $this->GetStepInfo(); + + return $aStepInfo['title'] ?? 'Modules selection'; + } + + public function GetPossibleSteps() + { + return [WizStepModulesChoice::class, WizStepDataAudit::class]; + } + + public function GetAddedAndRemovedExtensions($aSelectedExtensions) + { + $aExtensionsAdded = []; + $aExtensionsRemoved = []; + $aExtensionsNotUninstallable = []; + foreach ($this->oExtensionsMap->GetAllExtensionsWithPreviouslyInstalled() as $oExtension) { + /* @var \iTopExtension $oExtension */ + $bSelected = in_array($oExtension->sCode, $aSelectedExtensions); + if ($oExtension->bInstalled && !$bSelected) { + $aExtensionsRemoved[$oExtension->sCode] = $oExtension->sLabel; + if (!$oExtension->CanBeUninstalled() || $oExtension->sSource === iTopExtension::SOURCE_REMOTE) { + $aExtensionsNotUninstallable[$oExtension->sCode] = true; + } + } elseif (!$oExtension->bInstalled && $bSelected) { + $aExtensionsAdded[$oExtension->sCode] = $oExtension->sLabel; + } + } + + return [$aExtensionsAdded, $aExtensionsRemoved, $aExtensionsNotUninstallable]; + } + + public function UpdateWizardStateAndGetNextStep($bMoveForward = true): WizardState + { + // Accumulates the selected modules: + $index = $this->GetStepIndex(); + + // use json_encode:decode to store a hash array: step_id => array(input_name => selected_input_id) + $aSelectedChoices = json_decode($this->oWizard->GetParameter('selected_components', '{}'), true); + $aSelected = utils::ReadParam('choice', []); + $aSelectedChoices[$index] = $aSelected; + $this->oWizard->SetParameter('selected_components', json_encode($aSelectedChoices)); + + if ($this->GetStepInfo($index) == null) { + throw new Exception('Internal error: invalid step "'.$index.'" for the choice of modules.'); + } elseif ($bMoveForward) { + if ($this->GetStepInfo(1 + $index) != null) { + return new WizardState(WizStepModulesChoice::class, (string)($index + 1)); + } else { + // Exiting this step of the wizard, let's convert the selection into a list of modules + $aModules = []; + $aExtensions = []; + $sDisplayChoices = '
      '; + for ($i = 0; $i <= $index; $i++) { + $aStepInfo = $this->GetStepInfo($i); + $sDisplayChoices .= $this->GetSelectedModules($aStepInfo, $aSelectedChoices[$i], $aModules, '', '', $aExtensions); + } + $sDisplayChoices .= '
    '; + if (class_exists('CreateITILProfilesInstaller')) { + $this->oWizard->SetParameter('old_addon', true); + } + + [$aExtensionsAdded, $aExtensionsRemoved, $aExtensionsNotUninstallable] = $this->GetAddedAndRemovedExtensions($aExtensions); + $this->oWizard->SetParameter('selected_modules', json_encode(array_keys($aModules))); + $this->oWizard->SetParameter('selected_extensions', json_encode($aExtensions)); + $this->oWizard->SetParameter('display_choices', $sDisplayChoices); + $this->oWizard->SetParameter('added_extensions', json_encode($aExtensionsAdded)); + $this->oWizard->SetParameter('removed_extensions', json_encode($aExtensionsRemoved)); + $this->oWizard->SetParameter('extensions_not_uninstallable', json_encode(array_keys($aExtensionsNotUninstallable))); + + return new WizardState(WizStepDataAudit::class); + } + + } + //Unused when going backward + return new WizardState(WizStepModulesChoice::class, (string)($index - 1)); + } + + public function GetWizardSteps(): array + { + $aSteps = [ + ["class" => "WizStepWelcome","state" => ""], + ["class" => "WizStepInstallOrUpgrade","state" => ""], + ["class" => "WizStepDetectedInfo","state" => ""], + ["class" => "WizStepUpgradeMiscParams","state" => ""], + ]; + $i = 0; + $this->aSteps = null; + while (null != $this->GetStepInfo($i)) { + $this->aSteps = null; + $aSteps [] = ["class" => "WizStepModulesChoice","state" => "$i"]; + $i++; + } + + return $aSteps; + } + + public function GetSelectedComponents(array $aSteps, string $sSelectedExtensionJson): array + { + $aExtensions = json_decode($sSelectedExtensionJson, true); + $aRes = []; + foreach ($aSteps as $aStepInfo) { + $aStepRes = []; + $this->ProcessOptions("", $aStepInfo, $aExtensions, $aStepRes); + $this->ProcessAlternatives("", $aStepInfo, $aExtensions, $aStepRes); + $aRes [] = $aStepRes; + } + + return $aRes; + } + + public function ProcessOptions(string $sCurrentIndex, array $aInfo, array $aExtensions, array &$aStepRes) + { + $aOptions = $aInfo["options"] ?? null; + if (is_null($aOptions) || !is_array($aOptions)) { + return; + } + + foreach ($aOptions as $i => $aOptionsInfo) { + $sExtensionCode = $aOptionsInfo["extension_code"] ?? null; + + if (in_array($sExtensionCode, $aExtensions)) { + $aStepRes = $this->ProcessSelectedOption($sCurrentIndex, $i, $aStepRes, $aOptionsInfo, $aExtensions); + } + } + } + + public function ProcessAlternatives(string $sCurrentIndex, array $aInfo, array $aExtensions, array &$aStepRes) + { + $aAlternatives = $aInfo["alternatives"] ?? null; + if (is_null($aAlternatives) || ! is_array($aAlternatives)) { + return; + } + + foreach ($aAlternatives as $i => $aAlternativeInfo) { + $sExtensionCode = $aAlternativeInfo["extension_code"] ?? null; + + if (in_array($sExtensionCode, $aExtensions)) { + $aStepRes = $this->ProcessSelectedOption($sCurrentIndex, $i, $aStepRes, $aAlternativeInfo, $aExtensions); + break; + } + } + } + + /** + * @param string $sCurrentIndex + * @param int|string $i + * @param array $aStepRes + * @param mixed $aOptionsInfo + * @param array $aExtensions + * + * @return array + */ + public function ProcessSelectedOption(string $sCurrentIndex, int|string $i, array $aStepRes, mixed $aOptionsInfo, array $aExtensions): array + { + $sNextIndex = "{$sCurrentIndex}_{$i}"; + $aStepRes[$sNextIndex] = $sNextIndex; + + $aSubOptions = $aOptionsInfo['sub_options'] ?? null; + if (!is_null($aSubOptions) && is_array($aSubOptions)) { + $this->ProcessOptions($sNextIndex, $aSubOptions, $aExtensions, $aStepRes); + $this->ProcessAlternatives($sNextIndex, $aSubOptions, $aExtensions, $aStepRes); + } + + $this->ProcessAlternatives($sNextIndex, $aOptionsInfo, $aExtensions, $aStepRes); + + return $aStepRes; + } + + public function Display(SetupPage $oPage): void + { + $this->DisplayStep($oPage); + } + + /** + * @param \SetupPage $oPage + * + * @throws \Exception + */ + protected function DisplayStep($oPage) + { + // Sanity check (not stopper, to let developers go further...) + if (! is_null($this->oMissingDependencyException)) { + $oPage->warning($this->oMissingDependencyException->getHtmlDesc(), $this->oMissingDependencyException->getMessage()); + } + + $this->bUpgrade = ($this->oWizard->GetParameter('install_mode') != 'install'); + $aStepInfo = $this->GetStepInfo(); + $oPage->add_style("div.choice { margin: 0.5em;}"); + $oPage->add_style("div.choice a { text-decoration:none; font-weight: bold; color: #1C94C4 }"); + $oPage->add_style("div.description { margin-left: 2em; }"); + $oPage->add_style("input.unremovable { accent-color: orangered;}"); + + $sManualInstallError = SetupUtils::CheckManualInstallDirEmpty( + $this->aAnalyzeInstallationModules, + $this->oWizard->GetParameter('extensions_dir', 'extensions') + ); + if ($sManualInstallError !== '') { + $oPage->warning($sManualInstallError); + } + + $oPage->add('
    '); + $sBannerPath = isset($aStepInfo['banner']) ? $aStepInfo['banner'] : ''; + if (!empty($sBannerPath)) { + if (substr($sBannerPath, 0, 1) == '/') { + // absolute path, means relative to APPROOT + $sBannerUrl = utils::GetDefaultUrlAppRoot(true).$sBannerPath; + } else { + // relative path: i.e. relative to the directory containing the XML file + $sFullPath = dirname($this->GetSourceFilePath()).'/'.$sBannerPath; + $sRealPath = realpath($sFullPath); + $sBannerUrl = utils::GetDefaultUrlAppRoot(true).str_replace(realpath(APPROOT), '', $sRealPath); + } + $oPage->add(''); + } + $sDescription = $aStepInfo['description'] ?? ''; + $oPage->add(''.$sDescription.''); + $oPage->add('
    '); + + // Build the default choices + $aDefaults = $this->GetDefaults($aStepInfo, $this->aAnalyzeInstallationModules); + $index = $this->GetStepIndex(); + + // retrieve the saved selection + // use json_encode:decode to store a hash array: step_id => array(input_name => selected_input_id) + $aParameters = json_decode($this->oWizard->GetParameter('selected_components', '{}'), true); + if (!isset($aParameters[$index])) { + $aParameters[$index] = $aDefaults; + } + $aSelectedComponents = $aParameters[$index]; + + $oPage->add('
    '); + $this->DisplayOptions($oPage, $aStepInfo, $aSelectedComponents, $aDefaults); + $oPage->add('
    '); + + $oPage->add_script( + <<add_ready_script( + <<bChoicesFromDatabase) { + $this->GuessDefaultsFromModules($aInfo, $aDefaults, $aModules, $sParentId); + } else { + $this->GetDefaultsFromDatabase($aInfo, $aDefaults, $sParentId); + } + return $aDefaults; + } + + protected function GetDefaultsFromDatabase($aInfo, &$aDefaults, $sParentId) + { + $aOptions = isset($aInfo['options']) ? $aInfo['options'] : []; + foreach ($aOptions as $index => $aChoice) { + $sChoiceId = $sParentId.self::$SEP.$index; + if ($this->bUpgrade) { + if ($this->oExtensionsMap->IsMarkedAsChosen($aChoice['extension_code'])) { + $aDefaults[$sChoiceId] = $sChoiceId; + } + } elseif (isset($aChoice['default']) && $aChoice['default']) { + $aDefaults[$sChoiceId] = $sChoiceId; + } + // Recurse for sub_options (if any) + if (isset($aChoice['sub_options'])) { + $this->GetDefaultsFromDatabase($aChoice['sub_options'], $aDefaults, $sChoiceId); + } + } + + $aAlternatives = $aInfo['alternatives'] ?? []; + $sChoiceName = null; + foreach ($aAlternatives as $index => $aChoice) { + $sChoiceId = $sParentId.self::$SEP.$index; + if ($sChoiceName == null) { + $sChoiceName = $sChoiceId; // All radios share the same name + } + if ($this->bUpgrade) { + if ($this->oExtensionsMap->IsMarkedAsChosen($aChoice['extension_code'])) { + $aDefaults[$sChoiceName] = $sChoiceId; + } + } elseif (isset($aChoice['default']) && $aChoice['default']) { + $aDefaults[$sChoiceName] = $sChoiceId; + } + // Recurse for sub_options (if any) + if (isset($aChoice['sub_options'])) { + $this->GetDefaultsFromDatabase($aChoice['sub_options'], $aDefaults, $sChoiceId); + } + } + } + + /** + * Try to guess the user choices based on the current list of installed modules... + * @param array $aInfo + * @param array $aDefaults + * @param array $aModules + * @param string $sParentId + * @return array + */ + protected function GuessDefaultsFromModules($aInfo, &$aDefaults, $aModules, $sParentId = '') + { + $aRetScore = []; + $aScores = []; + + $aOptions = isset($aInfo['options']) ? $aInfo['options'] : []; + foreach ($aOptions as $index => $aChoice) { + $sChoiceId = $sParentId.self::$SEP.$index; + $aScores[$sChoiceId] = []; + if (!$this->bUpgrade && isset($aChoice['default']) && $aChoice['default']) { + $aDefaults[$sChoiceId] = $sChoiceId; + } + if ($this->bUpgrade) { + // In upgrade mode, the defaults are the installed modules + foreach ($aChoice['modules'] as $sModuleId) { + if ($aModules[$sModuleId]['installed_version'] != '') { + // A module corresponding to this choice is installed + $aScores[$sChoiceId][$sModuleId] = true; + } + } + // Used for migration from 1.3.x or before + // Accept that the new version can have one new module than the previous version + // The option is still selected + $iSelected = count($aScores[$sChoiceId]); + $iNeeded = count($aChoice['modules']); + if (($iSelected > 0) && (($iNeeded - $iSelected) < 2)) { + // All the modules are installed, this choice is selected + $aDefaults[$sChoiceId] = $sChoiceId; + } + $aRetScore = array_merge($aRetScore, $aScores[$sChoiceId]); + } + + if (isset($aChoice['sub_options'])) { + $aScores[$sChoiceId] = array_merge($aScores[$sChoiceId], $this->GuessDefaultsFromModules($aChoice['sub_options'], $aDefaults, $aModules, $sChoiceId)); + } + } + + $aAlternatives = isset($aInfo['alternatives']) ? $aInfo['alternatives'] : []; + $sChoiceName = null; + foreach ($aAlternatives as $index => $aChoice) { + $sChoiceId = $sParentId.self::$SEP.$index; + $aScores[$sChoiceId] = []; + if ($sChoiceName == null) { + $sChoiceName = $sChoiceId; + } + if (!$this->bUpgrade && isset($aChoice['default']) && $aChoice['default']) { + $aDefaults[$sChoiceName] = $sChoiceId; + } + if (isset($aChoice['sub_options'])) { + // By default (i.e. install-mode), sub options can only be checked if the parent option is checked by default + if ($this->bUpgrade || (isset($aChoice['default']) && $aChoice['default'])) { + $aScores[$sChoiceId] = $this->GuessDefaultsFromModules($aChoice['sub_options'], $aDefaults, $aModules, $sChoiceId); + } + } + } + + $iMaxScore = 0; + if ($this->bUpgrade && (count($aAlternatives) > 0)) { + // The installed choices have precedence over the 'default' choices + // In case several choices share the same base modules, let's weight the alternative choices + // based on their number of installed modules + $sChoiceName = null; + + foreach ($aAlternatives as $index => $aChoice) { + $sChoiceId = $sParentId.self::$SEP.$index; + if ($sChoiceName == null) { + $sChoiceName = $sChoiceId; + } + if (array_key_exists('modules', $aChoice)) { + foreach ($aChoice['modules'] as $sModuleId) { + if ($aModules[$sModuleId]['installed_version'] != '') { + // A module corresponding to this choice is installed, increase the score of this choice + if (!isset($aScores[$sChoiceId])) { + $aScores[$sChoiceId] = []; + } + $aScores[$sChoiceId][$sModuleId] = true; + $iMaxScore = max($iMaxScore, count($aScores[$sChoiceId])); + } + } + //if (count($aScores[$sChoiceId]) == count($aChoice['modules'])) + //{ + // $iScore += 100; // Bonus for the parent when a choice is complete + //} + $aRetScore = array_merge($aRetScore, $aScores[$sChoiceId]); + } + $iMaxScore = max($iMaxScore, isset($aScores[$sChoiceId]) ? count($aScores[$sChoiceId]) : 0); + } + } + if ($iMaxScore > 0) { + $aNumericScores = []; + foreach ($aScores as $sChoiceId => $aModules) { + $aNumericScores[$sChoiceId] = count($aModules); + } + // The choice with the bigger score wins ! + asort($aNumericScores, SORT_NUMERIC); + $aKeys = array_keys($aNumericScores); + $sBetterChoiceId = array_pop($aKeys); + $aDefaults[$sChoiceName] = $sBetterChoiceId; + } + // echo "Scores:
    ".print_r($aScores, true)."

    "; + // echo "Defaults:
    ".print_r($aDefaults, true)."

    "; + return $aRetScore; + } + + private function GetPhpExpressionEvaluator(): PhpExpressionEvaluator + { + if (!isset($this->oPhpExpressionEvaluator)) { + $this->oPhpExpressionEvaluator = new PhpExpressionEvaluator([], ModuleFileReader::STATIC_CALL_AUTOSELECT_WHITELIST); + } + + return $this->oPhpExpressionEvaluator; + } + + /** + * Converts the list of selected "choices" into a list of "modules": take into account the selected and the mandatory modules + * + * @param array $aInfo Info about the "choice" array('options' => array(...), 'alternatives' => array(...)) + * @param array $aSelectedChoices List of selected choices array('name' => 'selected_value_id') + * @param array $aModules Return parameter: List of selected modules array('module_id' => true) + * @param string $sParentId Used for recursion + * + * @return string A text representation of what will be installed + * @throws \Exception + */ + public function GetSelectedModules($aInfo, $aSelectedChoices, &$aModules, $sParentId = '', $sDisplayChoices = '', &$aSelectedExtensions = null) + { + if ($sParentId == '') { + // Check once (before recursing) that the hidden modules are selected + foreach ($this->aAnalyzeInstallationModules as $sModuleId => $aModule) { + if (($sModuleId != ROOT_MODULE) && !isset($aModules[$sModuleId])) { + if (($aModule['category'] == 'authentication') || (!$aModule['visible'] && !isset($aModule['auto_select']))) { + $aModules[$sModuleId] = true; + $sDisplayChoices .= '
  • '.$aModule['label'].' (hidden)
  • '; + } + } + } + } + $aOptions = $aInfo['options'] ?? []; + foreach ($aOptions as $index => $aChoice) { + $sChoiceId = $sParentId.self::$SEP.$index; + $aModuleInfo = []; + // Get the extension corresponding to the choice + foreach ($this->oExtensionsMap->GetAllExtensions() as $sExtensionVersion => $oExtension) { + if (utils::StartsWith($sExtensionVersion, $aChoice['extension_code'].'/')) { + $aModuleInfo = $oExtension->aModuleInfo; + break; + } + } + if ((isset($aChoice['mandatory']) && $aChoice['mandatory']) || + (isset($aSelectedChoices[$sChoiceId]) && ($aSelectedChoices[$sChoiceId] == $sChoiceId))) { + $sDisplayChoices .= '
  • '.$aChoice['title'].'
  • '; + if (isset($aChoice['modules'])) { + if (count($aChoice['modules']) === 0 && (!isset($aChoice['missing']) || $aChoice['missing'] === false)) { + SetupLog::Error(__METHOD__, null, ['choice' => $aChoice]); + throw new Exception('Extension '.$aChoice['extension_code'].' does not have any module associated'); + } + foreach ($aChoice['modules'] as $sModuleId) { + $bSelected = true; + if (isset($aModuleInfo[$sModuleId])) { + /** @var array $aCurrentModuleInfo */ + $aCurrentModuleInfo = $aModuleInfo[$sModuleId]; + if (isset($aCurrentModuleInfo['auto_select'])) { + // Check the module selection + try { + SetupInfo::SetSelectedModules($aModules); + $bSelected = $this->GetPhpExpressionEvaluator()->ParseAndEvaluateBooleanExpression($aCurrentModuleInfo['auto_select']); + } catch (ModuleFileReaderException $e) { + //logged already + $bSelected = false; + } + } + } + if ($bSelected) { + $aModules[$sModuleId] = true; // store the Id of the selected module + SetupInfo::SetSelectedModules($aModules); + } + } + } + if ($aSelectedExtensions !== null) { + $aSelectedExtensions[] = $aChoice['extension_code']; + } + // Recurse only for selected choices + if (isset($aChoice['sub_options'])) { + $sDisplayChoices .= '
      '; + $sDisplayChoices = $this->GetSelectedModules($aChoice['sub_options'], $aSelectedChoices, $aModules, $sChoiceId, $sDisplayChoices, $aSelectedExtensions); + $sDisplayChoices .= '
    '; + } + $sDisplayChoices .= ''; + } + } + + $aAlternatives = $aInfo['alternatives'] ?? []; + $sChoiceName = null; + foreach ($aAlternatives as $index => $aChoice) { + $sChoiceId = $sParentId.self::$SEP.$index; + if ($sChoiceName == null) { + $sChoiceName = $sChoiceId; + } + if ((isset($aChoice['mandatory']) && $aChoice['mandatory']) || + (isset($aSelectedChoices[$sChoiceName]) && ($aSelectedChoices[$sChoiceName] == $sChoiceId))) { + $sDisplayChoices .= '
  • '.$aChoice['title'].'
  • '; + if ($aSelectedExtensions !== null) { + $aSelectedExtensions[] = $aChoice['extension_code']; + } + if (isset($aChoice['modules'])) { + foreach ($aChoice['modules'] as $sModuleId) { + $aModules[$sModuleId] = true; // store the Id of the selected module + } + } + // Recurse only for selected choices + if (isset($aChoice['sub_options'])) { + $sDisplayChoices .= '
      '; + $sDisplayChoices = $this->GetSelectedModules($aChoice['sub_options'], $aSelectedChoices, $aModules, $sChoiceId, $sDisplayChoices, $aSelectedExtensions); + $sDisplayChoices .= '
    '; + } + $sDisplayChoices .= ''; + } + } + if ($sParentId == '') { + // Last pass (after all the user's choices are turned into "selected" modules): + // Process 'auto_select' modules for modules that are not already selected + do { + // Loop while new modules are added... + $bModuleAdded = false; + foreach ($this->aAnalyzeInstallationModules as $sModuleId => $aModule) { + if (($sModuleId != ROOT_MODULE) && !array_key_exists($sModuleId, $aModules) && isset($aModule['auto_select'])) { + try { + SetupInfo::SetSelectedModules($aModules); + $bSelected = $this->GetPhpExpressionEvaluator()->ParseAndEvaluateBooleanExpression($aModule['auto_select']); + if ($bSelected) { + $aModules[$sModuleId] = true; // store the Id of the selected module + $sDisplayChoices .= '
  • '.$aModule['label'].' (auto_select)
  • '; + $bModuleAdded = true; + } + } catch (ModuleFileReaderException $e) { + //logged already + $sDisplayChoices .= '
  • Warning: auto_select failed with exception ('.$e->getMessage().') for module "'.$sModuleId.'"
  • '; + } + } + } + } while ($bModuleAdded); + } + + return $sDisplayChoices; + } + + protected function GetStepIndex() + { + switch ($this->sCurrentState) { + case 'start_install': + case 'start_upgrade': + $index = 0; + break; + + default: + $index = (int)$this->sCurrentState; + } + return $index; + } + + protected function GetStepInfo($idx = null) + { + $index = $idx ?? $this->GetStepIndex(); + $bRemoteExtensionsShouldBeMandatory = !$this->oWizard->GetParameter('force-uninstall', false); + if (is_null($this->aSteps)) { + $this->oWizard->SetParameter('additional_extensions_modules', json_encode([])); // Default value, no additional extensions + + if (@file_exists($this->GetSourceFilePath())) { + // Found an "installation.xml" file, let's use this definition for the wizard + $aParams = new XMLParameters($this->GetSourceFilePath()); + $this->aSteps = $aParams->Get('steps', []); + if ($index + 1 >= count($this->aSteps)) { + //make sure we also cache next step as well + $aOptions = $this->oExtensionsMap->GetAllExtensionsOptionInfo($bRemoteExtensionsShouldBeMandatory); + // Display this step of the wizard only if there is something to display + if (count($aOptions) > 0) { + $this->aSteps[] = [ + 'title' => 'Extensions', + 'description' => '

    Select additional extensions to install. You can launch the installation again to install new extensions or remove installed ones.

    ', + 'banner' => '/images/icons/icons8-puzzle.svg', + 'options' => $aOptions, + ]; + $this->oWizard->SetParameter('additional_extensions_modules', json_encode($aOptions)); + } + } + } else { + //legacy product (1.x/no installation.xml) + $aOptions = $this->oExtensionsMap->GetAllExtensionsOptionInfo($bRemoteExtensionsShouldBeMandatory); + + // No wizard configuration provided, build a standard one with just one big list. All items are mandatory, only works when there are no conflicted modules. + $this->aSteps = [ + [ + 'title' => 'Modules Selection', + 'description' => '

    Select the modules to install. You can launch the installation again to install new modules, but you cannot remove already installed modules.

    ', + 'banner' => '/images/icons/icons8-apps-tab.svg', + 'options' => $aOptions, + ], + ]; + } + } + return $this->aSteps[$index] ?? null; + } + + public function ComputeChoiceFlags(array $aChoice, string $sChoiceId, array $aSelectedComponents, bool $bAllDisabled, bool $bDisableUninstallCheck, bool $bUpgradeMode) + { + $oITopExtension = $this->oExtensionsMap->GetFromExtensionCode($aChoice['extension_code']); + //If the extension is missing from disk, it won't exist in the ExtensionsMap, thus returning null + $bCanBeUninstalled = isset($aChoice['uninstallable']) ? $aChoice['uninstallable'] === true || $aChoice['uninstallable'] === 'yes' : $oITopExtension->CanBeUninstalled(); + $bSelected = isset($aSelectedComponents[$sChoiceId]) && ($aSelectedComponents[$sChoiceId] === $sChoiceId); + $bMissingFromDisk = isset($aChoice['missing']) && $aChoice['missing'] === true; + $bMandatory = (isset($aChoice['mandatory']) && $aChoice['mandatory']); + $bInstalled = $bMissingFromDisk || $oITopExtension->bInstalled; + + $bChecked = $bSelected; + $bDisabled = false; + if ($bMissingFromDisk) { + $bDisabled = true; + $bChecked = false; + } elseif ($bMandatory) { + $bDisabled = true; + $bChecked = true; + } elseif ($bInstalled && !$bCanBeUninstalled && !$bDisableUninstallCheck) { + $bChecked = true; + $bDisabled = true; + } + + if ($bAllDisabled) { + $bDisabled = true; + } + + if (isset($aChoice['sub_options'])) { + $aOptions = $aChoice['sub_options']['options'] ?? []; + foreach ($aOptions as $index => $aSubChoice) { + $sSubChoiceId = $sChoiceId.self::$SEP.$index; + $aSubFlags = $this->ComputeChoiceFlags($aSubChoice, $sSubChoiceId, $aSelectedComponents, $bAllDisabled, $bDisableUninstallCheck, $bUpgradeMode); + if ($aSubFlags['checked']) { + $bChecked = true; + if ($aSubFlags['disabled']) { + //If some sub options are enabled and cannot be disabled, this choice should also cannot be disabled since it would disable all its sub options + $bDisabled = true; + } + } + + } + } + + return [ + 'uninstallable' => $bCanBeUninstalled, + 'missing' => $bMissingFromDisk, + 'installed' => $bInstalled, + 'disabled' => $bDisabled, + 'checked' => $bChecked, + ]; + } + + public function DisplayOptions($oPage, $aStepInfo, $aSelectedComponents, $aDefaults, $sParentId = '', $bAllDisabled = false) + { + $aOptions = $aStepInfo['options'] ?? []; + $aAlternatives = $aStepInfo['alternatives'] ?? []; + + $bDisableUninstallCheck = (bool)$this->oWizard->GetParameter('force-uninstall', false); + + foreach ($aOptions as $index => $aChoice) { + $sChoiceId = $sParentId.self::$SEP.$index; + $aFlags = $this->ComputeChoiceFlags($aChoice, $sChoiceId, $aSelectedComponents, $bAllDisabled, $bDisableUninstallCheck, $this->bUpgrade); + + if ($aFlags['disabled'] && !$aFlags['checked'] && !$aFlags['uninstallable'] && !$bDisableUninstallCheck) { + $this->bCanMoveForward = false;//Disable "Next" + } + + $this->DisplayChoice($oPage, $aChoice, $aSelectedComponents, $aDefaults, $sChoiceId, $sChoiceId, $aFlags); + } + + $sChoiceName = null; + $bDisabled = false; + $sChoiceIdNone = null; + foreach ($aAlternatives as $index => $aChoice) { + $sChoiceId = $sParentId.self::$SEP.$index; + if ($sChoiceName == null) { + $sChoiceName = $sChoiceId; // All radios share the same name + } + //Defaults contains previous installation choices during upgrade + $bIsDefault = array_key_exists($sChoiceName, $aDefaults) && ($aDefaults[$sChoiceName] === $sChoiceId); + $bMandatory = (isset($aChoice['mandatory']) && $aChoice['mandatory']) || ($this->bUpgrade && $bIsDefault); + if ($bMandatory || $bAllDisabled) { + // One choice is mandatory, all alternatives are disabled + $bDisabled = true; + } + if ((!isset($aChoice['sub_options']) || (count($aChoice['sub_options']) === 0)) && (!isset($aChoice['modules']) || (count($aChoice['modules']) === 0))) { + //If there is no modules in the choice AND it has no sub choices, it is an empty choice. + $sChoiceIdNone = $sChoiceId; // the "None" / empty choice + } + } + + if (!array_key_exists($sChoiceName, $aDefaults) || ($aDefaults[$sChoiceName] === $sChoiceIdNone)) { + // The "none" choice does not disable the selection !! + $bDisabled = false; + } + + foreach ($aAlternatives as $index => $aChoice) { + $sChoiceId = $sParentId.self::$SEP.$index; + $bSelected = isset($aSelectedComponents[$sChoiceName]) && ($aSelectedComponents[$sChoiceName] === $sChoiceId); + if (!isset($aSelectedComponents[$sChoiceName]) && ($sChoiceIdNone !== null)) { + // No choice selected, select the "None" option + $bSelected = ($sChoiceId === $sChoiceIdNone); + } + + $aFlags = $this->ComputeChoiceFlags($aChoice, $sChoiceId, $aSelectedComponents, $bAllDisabled, $bDisableUninstallCheck, $this->bUpgrade); + //ComputeChoiceFlags does not completely compute alternative flags + $aFlags['disabled'] = $bDisabled; + $aFlags['checked'] = $bSelected; + $this->DisplayChoice($oPage, $aChoice, $aSelectedComponents, $aDefaults, $sChoiceName, $sChoiceId, $aFlags, 'radio'); + } + } + + protected function DisplayChoice($oPage, $aChoice, $aSelectedComponents, $aDefaults, $sChoiceName, $sChoiceId, $aFlags, $sInputType = 'checkbox') + { + $sMoreInfo = (isset($aChoice['more_info']) && ($aChoice['more_info'] != '')) ? ' + + + ' : ''; + $sDescription = isset($aChoice['description']) ? utils::EscapeHtml($aChoice['description']) : ''; + $sId = utils::EscapeHtml($aChoice['extension_code']); + $sDataId = 'data-id="'.utils::EscapeHtml($aChoice['extension_code']).'"'; + $sDisabled = $aFlags['disabled'] ? ' disabled data-disabled="disabled"' : ''; + $sChecked = $aFlags['checked'] ? ' checked ' : ''; + $sHiddenInput = $aFlags['disabled'] && $aFlags['checked'] ? '' : ''; + + $sTooltip = ''; + if ($aFlags['missing']) { + $sTooltip .= '
    source removed
    '; + } + if ($aFlags['installed']) { + $sTooltip .= '
    installed
    '; + + $sTooltip .= '
    to be uninstalled
    '; + } else { + $sTooltip .= '
    to be installed
    '; + $sTooltip .= '
    not installed
    '; + } + if (!$aFlags['uninstallable']) { + $sTooltip .= '
    cannot be uninstalled
    '; + } + + $sMetadata = ''; + if (isset($aChoice['version']) && isset($aChoice['source_label'])) { + $sMetadata = 'v'.$aChoice['version'].''.$aChoice['source_label'].''; + } + $sChoiceDisabled = $aFlags['disabled'] && !$aFlags['checked'] ? 'choice-disabled' : ''; + + $oPage->add(' +
    +
    + + '.$sHiddenInput.' +
    +
    +
    + + '.$sMoreInfo.' + '.$sTooltip.' +
    + +
    + '.$sDescription.' + '); + $bSubOptionsDisabled = $aFlags['disabled'] && (!$aFlags['installed'] || $sInputType === 'checkbox'); + if (isset($aChoice['sub_options'])) { + $oPage->add('
    '); + $this->DisplayOptions($oPage, $aChoice['sub_options'], $aSelectedComponents, $aDefaults, $sChoiceId, $bSubOptionsDisabled); + $oPage->add('
    '); + } + $oPage->add(' +
    +
    +
    + '); + } + + protected function GetSourceFilePath() + { + $sSourceDir = $this->oWizard->GetParameter('source_dir'); + return $sSourceDir.'/installation.xml'; + } + + public function CanMoveForward() + { + return true; + } + + public function JSCanMoveForward() + { + + return $this->bCanMoveForward ? 'return true;' : 'return false;'; + } + + public function GetNextButtonLabel() + { + if (!$this->bCanMoveForward) { + return 'Non-uninstallable extension missing'; + } + + if ($this->GetStepInfo(1 + $this->GetStepIndex()) === null) { + return 'Check compatibility'; + } + + return 'Next'; + } + +} diff --git a/setup/wizardsteps/WizStepSummary.php b/setup/wizardsteps/WizStepSummary.php new file mode 100644 index 0000000000..f8cefaa9dc --- /dev/null +++ b/setup/wizardsteps/WizStepSummary.php @@ -0,0 +1,263 @@ +oWizard->GetParameter('mode', 'install'); + if ($sMode == 'install') { + return 'Ready to install'; + + } else { + return 'Ready to upgrade'; + } + } + + public function GetPossibleSteps() + { + return [WizStepInstall::class]; + } + + /** + * Returns the label for the " Next >> " button + * @return string The label for the button + */ + public function GetNextButtonLabel() + { + return 'Install'; + } + + public function CanMoveForward() + { + if ($this->CheckDependencies()) { + return true; + } else { + return false; + } + } + + public function UpdateWizardStateAndGetNextStep($bMoveForward = true): WizardState + { + $this->oWizard->SaveParameter('db_backup', false); + $this->oWizard->SaveParameter('db_backup_path', ''); + return new WizardState(WizStepInstall::class); + } + + public function Display(SetupPage $oPage): void + { + + $aInstallParams = $this->BuildConfig(); + + $sMode = $aInstallParams['mode']; + + $sDestination = ITOP_APPLICATION.(($sMode == 'install') ? ' version '.ITOP_VERSION.' is about to be installed ' : ' is about to be upgraded '); + $sDBDescription = ' existing database '.$aInstallParams['database']['name'].''; + if (($sMode == 'install') && ($this->oWizard->GetParameter('create_db') == 'yes')) { + $sDBDescription = ' new database '.$aInstallParams['database']['name'].''; + } + $sDestination .= 'into the '.$sDBDescription.' on the server '.$aInstallParams['database']['server'].'.'; + $oPage->add('

    '.$sDestination.'

    '); + + $oPage->add('
    Installation Parameters'); + $oPage->add('
    '); + + $oPage->add('
    Extensions to be installed'); + $aExtensionsAdded = json_decode($this->oWizard->GetParameter('added_extensions'), true) ?? []; + + if (count($aExtensionsAdded) > 0) { + $sExtensionsAdded = '
      '; + foreach ($aExtensionsAdded as $sExtensionCode => $sLabel) { + $sExtensionsAdded .= '
    • '.$sLabel.'
    • '; + } + $sExtensionsAdded .= '
    '; + } else { + $sExtensionsAdded = '
    • No extension added.
    '; + } + $oPage->add($sExtensionsAdded); + $oPage->add('
    '); + $oPage->add('
    Extensions to be uninstalled'); + + $aExtensionsRemoved = json_decode($this->oWizard->GetParameter('removed_extensions'), true) ?? []; + $aExtensionsNotUninstallable = json_decode($this->oWizard->GetParameter('extensions_not_uninstallable')) ?? []; + if (count($aExtensionsRemoved) > 0) { + $sExtensionsRemoved = '
      '; + foreach ($aExtensionsRemoved as $sExtensionCode => $sLabel) { + if (in_array($sExtensionCode, $aExtensionsNotUninstallable)) { + $sExtensionsRemoved .= '
    • '.$sLabel.' (forced uninstallation)
    • '; + } else { + $sExtensionsRemoved .= '
    • '.$sLabel.'
    • '; + } + } + $sExtensionsRemoved .= '
    '; + } else { + $sExtensionsRemoved = '
    • No extension removed.
    '; + } + $oPage->add($sExtensionsRemoved); + $oPage->add('
    '); + + $oPage->add('
    Database Parameters
      '); + $oPage->add('
    • Server Name: '.$aInstallParams['database']['server'].'
    • '); + $oPage->add('
    • DB User Name: '.$aInstallParams['database']['user'].'
    • '); + $oPage->add('
    • DB user password: ***
    • '); + if (($sMode == 'install') && ($this->oWizard->GetParameter('create_db') == 'yes')) { + $oPage->add('
    • Database Name: '.$aInstallParams['database']['name'].' (will be created)
    • '); + } else { + $oPage->add('
    • Database Name: '.$aInstallParams['database']['name'].'
    • '); + } + if ($aInstallParams['database']['prefix'] != '') { + $oPage->add('
    • Prefix for the '.ITOP_APPLICATION.' tables: '.$aInstallParams['database']['prefix'].'
    • '); + } else { + $oPage->add('
    • Prefix for the '.ITOP_APPLICATION.' tables: none
    • '); + } + $oPage->add('
    '); + + $oPage->add('
    Data Model Configuration'); + $oPage->add($this->oWizard->GetParameter('display_choices')); + $oPage->add('
    '); + + $oPage->add('
    Other Parameters
      '); + if ($sMode == 'install') { + $oPage->add('
    • Default language: '.$aInstallParams['language'].'
    • '); + } + + $oPage->add('
    • URL to access the application: '.$aInstallParams['url'].'
    • '); + $oPage->add('
    • Graphviz\' dot path: '.$aInstallParams['graphviz_path'].'
    • '); + if ($aInstallParams['sample_data']) { + $oPage->add('
    • Sample data will be loaded into the database.
    • '); + } + if ($aInstallParams['old_addon']) { + $oPage->add('
    • Compatibility mode: Using the version 1.2 of the UserRightsProfiles add-on.
    • '); + } + $oPage->add('
    '); + + if ($sMode == 'install') { + $oPage->add('
    Administrator Account
      '); + $oPage->add('
    • Login: '.$aInstallParams['admin_account']['user'].'
    • '); + $oPage->add('
    • Password: '.$aInstallParams['admin_account']['pwd'].'
    • '); + $oPage->add('
    • Language: '.$aInstallParams['admin_account']['language'].'
    • '); + $oPage->add('
    '); + } + + $aMiscOptions = $aInstallParams['options']; + if (count($aMiscOptions) > 0) { + $oPage->add('
    Miscellaneous Options
      '); + foreach ($aMiscOptions as $sKey => $sValue) { + $oPage->add('
    • '.$sKey.': '.$sValue.'
    • '); + } + $oPage->add('
    '); + + } + + if (isset($aMiscOptions['generate_config'])) { + $oDoc = new DOMDocument('1.0', 'UTF-8'); + $oDoc->preserveWhiteSpace = false; + $oDoc->formatOutput = true; + $oParams = new PHPParameters(); + $oParams->LoadFromHash($aInstallParams); + $oParams->ToXML($oDoc, null, 'installation'); + $sXML = $oDoc->saveXML(); + $oPage->add('
    XML Config file
      ');
      +			$oPage->add(utils::EscapeHtml($sXML));
      +			$oPage->add('
    '); + } + + $oPage->add('
    '); // params_summary + $oPage->add('
    '); + + if (!$this->CheckDependencies()) { + $oPage->error($this->sDependencyIssue); + } + + if ($sMode !== 'install') { + $bDBBackup = $this->oWizard->GetParameter('db_backup', false); + $sDefaultBackupPath = utils::GetDataPath().'backups/manual/setup-'.date('Y-m-d_H_i'); + $sDBBackupPath = $this->oWizard->GetParameter('db_backup_path', $sDefaultBackupPath); + $sMySQLBinDir = $this->oWizard->GetParameter('mysql_bindir', null); + $aPreviousInstance = SetupUtils::GetPreviousInstance(APPROOT); + if ($aPreviousInstance['found']) { + $sMySQLBinDir = $aPreviousInstance['mysql_bindir']; + $this->oWizard->SaveParameter('mysql_bindir', $aPreviousInstance['mysql_bindir']); + } + $aBackupChecks = SetupUtils::CheckBackupPrerequisites($sDBBackupPath, $sMySQLBinDir); + $bCanBackup = true; + $sMySQLDumpMessage = ''; + foreach ($aBackupChecks as $oCheck) { + switch ($oCheck->iSeverity) { + case CheckResult::ERROR: + $bCanBackup = false; + $sMySQLDumpMessage .= '
    Error:'.$oCheck->sLabel.'
    '; + break; + case CheckResult::TRACE: + SetupLog::Ok($oCheck->sLabel); + break; + default: + $sMySQLDumpMessage .= '
    Success:'.$oCheck->sLabel.'
    '; + break; + } + } + $sChecked = ($bCanBackup && $bDBBackup) ? ' checked ' : ''; + $sDisabled = $bCanBackup ? '' : ' disabled '; + $oPage->add('
    '); + $oPage->add(''); + $oPage->add('
    Save the backup to:
    '); + $fFreeSpace = SetupUtils::CheckDiskSpace($sDBBackupPath); + $sMessage = ''; + if ($fFreeSpace !== false) { + $sMessage .= SetupUtils::HumanReadableSize($fFreeSpace).' free in '.dirname($sDBBackupPath); + } + $oPage->add($sMySQLDumpMessage.''.$sMessage.''); + + } + + $sAuthentToken = $this->oWizard->GetParameter('authent', ''); + $oPage->add(''); + + $oPage->add_ready_script( + <<oWizard->SaveParameter('application_url', ''); + $this->oWizard->SaveParameter('graphviz_path', ''); + $this->oWizard->SaveParameter('use_symbolic_links', false); + $this->oWizard->SaveParameter('force-uninstall', false); + return new WizardState(WizStepModulesChoice::class, 'start_upgrade'); + } + + public function Display(SetupPage $oPage): void + { + $sApplicationURL = $this->oWizard->GetParameter('application_url', utils::GetAbsoluteUrlAppRoot(true)); //Preserve existing configuration (except for the str_replace based joker $SERVER_NAME$ which is lost) + $sDefaultGraphvizPath = (strtolower(substr(PHP_OS, 0, 3)) === 'win') ? 'C:\\Program Files\\Graphviz\\bin\\dot.exe' : '/usr/bin/dot'; + $sGraphvizPath = $this->oWizard->GetParameter('graphviz_path', $sDefaultGraphvizPath); + $oPage->add('

    Additional parameters

    '); + $oPage->add('
    '); + $oPage->add('Application URL'); + $oPage->add(''); + $oPage->add(''); + $oPage->add('
    URL:
    '); + $oPage->add('
    Change the value above if the end-users will be accessing the application by another path due to a specific configuration of the web server.
    '); + $oPage->add('
    '); + $oPage->add('
    '); + $oPage->add('Path to Graphviz\' dot application'); + $oPage->add(''); + $oPage->add(''); + $oPage->add(''); + $oPage->add('
    Path:
    '); + $oPage->add(''); + $oPage->add('
    '); + $sAuthentToken = $this->oWizard->GetParameter('authent', ''); + $oPage->add(''); + $oPage->add_ready_script( + <<AddUseSymlinksFlagOption($oPage); + $this->AddForceUninstallFlagOption($oPage); + } + + public function AsyncAction(WebPage $oPage, $sCode, $aParameters) + { + switch ($sCode) { + case 'check_graphviz': + $sGraphvizPath = $aParameters['graphviz_path']; + $aCheck = SetupUtils::CheckGraphviz($sGraphvizPath); + + // N°2214 logging TRACE results + $aTraceCheck = CheckResult::FilterCheckResultArray($aCheck, [CheckResult::TRACE]); + foreach ($aTraceCheck as $oTraceCheck) { + SetupLog::Ok($oTraceCheck->sLabel); + } + + $aNonTraceCheck = array_diff($aCheck, $aTraceCheck); + foreach ($aNonTraceCheck as $oCheck) { + switch ($oCheck->iSeverity) { + case CheckResult::INFO: + $sStatus = 'ok'; + $sInfoExplanation = $oCheck->sLabel; + $sMessage = json_encode('
    '.$sInfoExplanation.'
    '); + break; + + default: + case CheckResult::ERROR: + case CheckResult::WARNING: + $sStatus = 'ko'; + $sErrorExplanation = $oCheck->sLabel; + $sMessage = json_encode('
    '.$sErrorExplanation.'
    '); + break; + } + $oPage->add_ready_script( + <<'); + } + else + { + $("#v_application_url").html(''); + } + bGraphviz = ($('#graphviz_path').val() != ''); + if (!bGraphviz) + { + // Does not prevent to move forward + $("#v_graphviz_path").html(''); + } + else + { + $("#v_graphviz_path").html(''); + } + return bRet; +EOF + ; + } +} diff --git a/setup/wizardsteps/WizStepWelcome.php b/setup/wizardsteps/WizStepWelcome.php new file mode 100644 index 0000000000..c89389a16c --- /dev/null +++ b/setup/wizardsteps/WizStepWelcome.php @@ -0,0 +1,138 @@ +> " button + * @return string The label for the button + */ + public function GetNextButtonLabel() + { + return 'Continue'; + } + + public function GetPossibleSteps() + { + return [WizStepInstallOrUpgrade::class]; + } + + public function UpdateWizardStateAndGetNextStep($bMoveForward = true): WizardState + { + $sUID = SetupUtils::CreateSetupToken(); + $this->oWizard->SetParameter('authent', $sUID); + return new WizardState(WizStepInstallOrUpgrade::class); + } + + public function Display(SetupPage $oPage): void + { + // Store the misc_options for the future... + $aMiscOptions = utils::ReadParam('option', [], false, 'raw_data'); + $sMiscOptions = $this->oWizard->GetParameter('misc_options', json_encode($aMiscOptions)); + $this->oWizard->SetParameter('misc_options', $sMiscOptions); + + $oPage->add(""); + $oPage->add_ready_script( + << 0) + { + alert("Internet Explorer version 10 or older is NOT supported! (Check that IE is not running in compatibility mode)"); + } +EOF + ); + $oPage->add('

    '.ITOP_APPLICATION.' Installation Wizard

    '); + $aResults = SetupUtils::CheckPhpAndExtensions(); + $this->bCanMoveForward = true; + $aInfo = []; + $aWarnings = []; + $aErrors = []; + foreach ($aResults as $oCheckResult) { + switch ($oCheckResult->iSeverity) { + case CheckResult::ERROR: + $aErrors[] = $oCheckResult->sLabel; + $this->bCanMoveForward = false; + break; + + case CheckResult::WARNING: + $aWarnings[] = $oCheckResult->sLabel; + break; + + case CheckResult::INFO: + $aInfo[] = $oCheckResult->sLabel; + break; + + case CheckResult::TRACE: + SetupLog::Ok($oCheckResult->sLabel); + break; + } + } + $sStyle = 'style="display:none;overflow:auto;"'; + $sToggleButtons = ''; + if (count($aErrors) > 0) { + $sStyle = 'overflow:auto;"'; + $sTitle = count($aErrors).' Error(s), '.count($aWarnings).' Warning(s).'; + $sH2Class = 'text-error'; + } elseif (count($aWarnings) > 0) { + $sTitle = count($aWarnings).' Warning(s) '.$sToggleButtons; + $sH2Class = 'text-warning'; + } else { + $sTitle = 'Ok. '.$sToggleButtons; + $sH2Class = 'text-valid'; + } + $oPage->add( + <<Prerequisites validation: $sTitle +
    +HTML + ); + foreach ($aErrors as $sText) { + $oPage->error($sText); + } + foreach ($aWarnings as $sText) { + $oPage->warning($sText); + } + foreach ($aInfo as $sText) { + $oPage->ok($sText); + } + $oPage->add('
    '); + if (!$this->bCanMoveForward) { + $oPage->p('Sorry, the installation cannot continue. Please fix the errors and reload this page to launch the installation again.'); + $oPage->p(''); + } + $oPage->add_ready_script('CheckDirectoryConfFilesPermissions("'.utils::GetItopVersionWikiSyntax().'")'); + } + + public function CanMoveForward() + { + return $this->bCanMoveForward; + } +} diff --git a/setup/wizardsteps/WizardState.php b/setup/wizardsteps/WizardState.php new file mode 100644 index 0000000000..4ae70229ef --- /dev/null +++ b/setup/wizardsteps/WizardState.php @@ -0,0 +1,21 @@ +sNextStep = $sNextStep; + $this->sCurrentState = $sCurrentState; + } + private string $sNextStep; + private string $sCurrentState; + + public function GetNextStep() + { + return $this->sNextStep; + } + public function GetState() + { + return $this->sCurrentState; + } +} diff --git a/setup/wizardsteps/WizardStep.php b/setup/wizardsteps/WizardStep.php new file mode 100644 index 0000000000..bad393a3e2 --- /dev/null +++ b/setup/wizardsteps/WizardStep.php @@ -0,0 +1,392 @@ + + * WizStepLicense WizStepDetectedInfo + * WizStepDBParams + + + * WizStepAdminAccount | | + * WizStepInstallMiscParams v +------> + * + WizStepLicense2 +--> WizStepUpgradeMiscParams + * | + + * +---> <-----------------------------------+ + * WizStepModulesChoice + * WizStepSummary + * WizStepDone + */ + +use Combodo\iTop\Application\WebPage\WebPage; + +/** + * Abstract class to build "steps" for the wizard controller + * If a step needs to maintain an internal "state" (for complex steps) + * then it's up to the derived class to implement the behavior based on + * the internal 'sCurrentState' variable. + * @copyright Copyright (C) 2010-2024 Combodo SAS + * @license http://opensource.org/licenses/AGPL-3.0 + */ +abstract class WizardStep +{ + /** + * A reference to the WizardController + * @var WizardController + */ + protected $oWizard; + /** + * Current 'state' of the wizard step. Simple 'steps' can ignore it + * @var string + */ + protected $sCurrentState; + + protected $bDependencyCheck = null; + protected $sDependencyIssue = null; + + /** + * Add post display stuff to the setup screen + * @param \SetupPage $oPage + * + * @return void + */ + public function PostFormDisplay(SetupPage $oPage) + { + } + + protected function CheckDependencies() + { + if (is_null($this->bDependencyCheck)) { + $aSelectedModules = json_decode($this->oWizard->GetParameter('selected_modules'), true); + $this->bDependencyCheck = true; + try { + SetupUtils::AnalyzeInstallation($this->oWizard, true, $aSelectedModules); + } catch (MissingDependencyException $e) { + $this->bDependencyCheck = false; + $this->sDependencyIssue = $e->getHtmlDesc(); + } + } + return $this->bDependencyCheck; + } + + public function __construct(WizardController $oWizard, $sCurrentState) + { + $this->oWizard = $oWizard; + $this->sCurrentState = $sCurrentState; + } + + public function GetState() + { + return $this->sCurrentState; + } + + /** + * Displays the wizard page for the current class/state + * The page can contain any number of "" fields, but no "
    ...
    " tag + * The name of the input fields (and their id if one is supplied) MUST NOT start with "_" + * (this is reserved for the wizard's own parameters) + * + * @param \SetupPage $oPage + * + * @return void + */ + abstract public function Display(SetupPage $oPage): void; + + /** + * Processes the page's parameters and (if moving forward) returns the next step/state to be displayed + * @param bool $bMoveForward True if the wizard is moving forward 'Next >>' button pressed, false otherwise + * @return WizardState array('class' => $sNextClass, 'state' => $sNextState) + */ + abstract public function UpdateWizardStateAndGetNextStep(bool $bMoveForward = true): WizardState; + + /** + * Returns the list of possible steps from this step forward + * @return array Array of strings (step classes) + */ + abstract public function GetPossibleSteps(); + + /** + * Returns title of the current step + * @return string The title of the wizard page for the current step + */ + abstract public function GetTitle(); + + /** + * Tells whether the parameters are Ok to move forward + * @return boolean True to move forward, false to stey on the same step + */ + public function ValidateParams() + { + return true; + } + + /** + * Tells whether this step/state is the last one of the wizard (dead-end) + * @return boolean True if the 'Next >>' button should be displayed + */ + public function CanMoveForward() + { + return true; + } + + /** + * Tells whether the user will come back to this step/state if he click on "Back" + * @return boolean True if the 'Back' button should display this step + */ + public function CanComeBack() + { + return true; + } + + /** + * Tells whether the "Next" button should be enabled interactively + * @return string A piece of javascript code returning either true or false + */ + public function JSCanMoveForward() + { + return 'return true;'; + } + + /** + * Returns the label for the " Next >> " button + * @return string The label for the button + */ + public function GetNextButtonLabel() + { + return 'Next'; + } + + /** + * Tells whether this step/state allows to go back or not + * @return boolean True if the '<< Back' button should be displayed + */ + public function CanMoveBackward() + { + return true; + } + + /** + * Tells whether the "Back" button should be enabled interactively + * @return string A piece of javascript code returning either true or false + */ + public function JSCanMoveBackward() + { + return 'return true;'; + } + + /** + * Tells whether this step of the wizard requires that the configuration file be writable + * @return bool True if the wizard will possibly need to modify the configuration at some point + */ + public function RequiresWritableConfig() + { + return true; + } + + /** + * Overload this function to implement asynchronous action(s) (AJAX) + * @param string $sCode The code of the action (if several actions need to be distinguished) + * @param array $aParameters The action's parameters name => value + */ + public function AsyncAction(WebPage $oPage, $sCode, $aParameters) + { + } +} + +/* + * Example of a simple Setup Wizard with some parameters to store + * the installation mode (install | upgrade) and a simple asynchronous + * (AJAX) action. + * + * The setup wizard is executed by the following code: + * + * $oWizard = new WizardController('Step1'); + * $oWizard->Run(); + * +class Step1 extends WizardStep +{ + public function GetTitle() + { + return 'Welcome'; + } + + public function GetPossibleSteps() + { + return array(Step2::class, Step2bis::class); + } + + public function ProcessParams($bMoveForward = true) + { + $sNextStep = ''; + $sInstallMode = utils::ReadParam('install_mode'); + if ($sInstallMode == 'install') + { + $this->oWizard->SetParameter('install_mode', 'install'); + $sNextStep = Step2::class; + } + else + { + $this->oWizard->SetParameter('install_mode', 'upgrade'); + $sNextStep = Step2bis::class; + + } + return array('class' => $sNextStep, 'state' => ''); + } + + public function Display(WebPage $oPage) + { + $oPage->p('This is Step 1!'); + $sInstallMode = $this->oWizard->GetParameter('install_mode', 'install'); + $sChecked = ($sInstallMode == 'install') ? ' checked ' : ''; + $oPage->p(' Install'); + $sChecked = ($sInstallMode == 'upgrade') ? ' checked ' : ''; + $oPage->p(' Upgrade'); + } +} + +class Step2 extends WizardStep +{ + public function GetTitle() + { + return 'Installation Parameters'; + } + + public function GetPossibleSteps() + { + return array(Step3::class); + } + + public function ProcessParams($bMoveForward = true) + { + return array('class' => Step3::class, 'state' => ''); + } + + public function Display(WebPage $oPage) + { + $oPage->p('This is Step 2! (Installation)'); + } +} + +class Step2bis extends WizardStep +{ + public function GetTitle() + { + return 'Upgrade Parameters'; + } + + public function GetPossibleSteps() + { + return array(Step2ter::class); + } + + public function ProcessParams($bMoveForward = true) + { + $sUpgradeInfo = utils::ReadParam('upgrade_info'); + $this->oWizard->SetParameter('upgrade_info', $sUpgradeInfo); + $sAdditionalUpgradeInfo = utils::ReadParam('additional_upgrade_info'); + $this->oWizard->SetParameter('additional_upgrade_info', $sAdditionalUpgradeInfo); + return array('class' => Step2ter::class, 'state' => ''); + } + + public function Display(WebPage $oPage) + { + $oPage->p('This is Step 2bis! (Upgrade)'); + $sUpgradeInfo = $this->oWizard->GetParameter('upgrade_info', ''); + $oPage->p('Type your name here: '); + $sAdditionalUpgradeInfo = $this->oWizard->GetParameter('additional_upgrade_info', ''); + $oPage->p('The installer replies: '); + + $oPage->add_ready_script("$('#upgrade_info').change(function() { + $('#v_upgrade_info').html(''); + WizardAsyncAction('', { upgrade_info: $('#upgrade_info').val() }); });"); + } + + public function AsyncAction(WebPage $oPage, $sCode, $aParameters) + { + usleep(300000); // 300 ms + $sName = $aParameters['upgrade_info']; + $sReply = addslashes("Hello ".$sName); + + $oPage->add_ready_script( +<< Step3::class, 'state' => ''); + } + + public function Display(WebPage $oPage) + { + $oPage->p('This is Step 2ter! (Upgrade)'); + } +} + +class Step3 extends WizardStep +{ + public function GetTitle() + { + return 'Installation Complete'; + } + + public function GetPossibleSteps() + { + return array(); + } + + public function ProcessParams($bMoveForward = true) + { + return array('class' => '', 'state' => ''); + } + + public function Display(WebPage $oPage) + { + $oPage->p('This is the FINAL Step'); + } + + public function CanMoveForward() + { + return false; + } +} + +End of the example */ diff --git a/setup/wizardsteps_autoload.php b/setup/wizardsteps_autoload.php new file mode 100644 index 0000000000..7ab7353fc7 --- /dev/null +++ b/setup/wizardsteps_autoload.php @@ -0,0 +1,22 @@ +GetObjectKey($oAttDef->GetTargetClass(), $iDstObj); if ($iExtKey == 0) { $iExtKey = -$iDstObj; // Convention: Unresolved keys are stored as negative ! @@ -353,8 +354,10 @@ class XMLDataLoader foreach ($oObjList as $oTargetObj) { $bChanged = false; $sClass = get_class($oTargetObj); + $iExtKey = -1; foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) { if (($oAttDef->IsExternalKey()) && ($oTargetObj->Get($sAttCode) < 0)) { // Convention unresolved key = negative + /** @var \Combodo\iTop\Core\AttributeDefinition\AttributeExternalKey $oAttDef */ $sTargetClass = $oAttDef->GetTargetClass(); $iTempKey = $oTargetObj->Get($sAttCode); diff --git a/sources/Application/Helper/Session.php b/sources/Application/Helper/Session.php index 5fc2b06222..ae800cf22b 100644 --- a/sources/Application/Helper/Session.php +++ b/sources/Application/Helper/Session.php @@ -8,7 +8,6 @@ namespace Combodo\iTop\Application\Helper; use Combodo\iTop\SessionTracker\SessionHandler; -use utils; /** * Session management @@ -22,58 +21,54 @@ class Session /** @var int|null */ public static $iSessionId = null; /** @var bool */ - protected static $bIsInitialized = false; - /** @var bool */ - protected static $bSessionStarted = false; - /** @var bool */ public static $bAllowCLI = false; public static function Start() { - if (self::IsModeCLI()) { + if (session_status() === PHP_SESSION_DISABLED) { return; } - if (!self::$bIsInitialized) { - SessionHandler::session_set_save_handler(); - session_name('itop-'.md5(APPROOT)); + if (self::IsInitialized()) { + // Session already started + self::$iSessionId = session_id(); + return; } - self::$bIsInitialized = true; - if (!self::$bSessionStarted) { - if (!is_null(self::$iSessionId)) { - if (session_id(self::$iSessionId) === false) { - session_regenerate_id(true); - } + SessionHandler::session_set_save_handler(); + session_name('itop-'.md5(APPROOT)); + + if (!is_null(self::$iSessionId)) { + if (session_id(self::$iSessionId) === false) { + session_regenerate_id(true); } - self::$bSessionStarted = session_start(); - self::$iSessionId = session_id(); } + session_start(); + self::$iSessionId = session_id(); } public static function RegenerateId($bDeleteOldSession = false) { - if (self::IsModeCLI()) { + if (session_status() === PHP_SESSION_DISABLED || headers_sent()) { return; } session_regenerate_id($bDeleteOldSession); - if (self::$bSessionStarted) { + if (session_status() === PHP_SESSION_ACTIVE) { self::WriteClose(); } - self::$bSessionStarted = session_start(); + session_start(); self::$iSessionId = session_id(); } public static function WriteClose() { - if (self::IsModeCLI()) { + if (session_status() === PHP_SESSION_DISABLED) { return; } - if (self::$bSessionStarted) { + if (session_status() === PHP_SESSION_ACTIVE) { session_write_close(); - self::$bSessionStarted = false; } } @@ -96,7 +91,7 @@ class Session $sSessionVar = &$sSessionVar[$key]; } $sSessionVar = $value; - if (!self::$bSessionStarted) { + if (session_status() !== PHP_SESSION_ACTIVE) { self::Start(); $_SESSION = $aSession; self::WriteClose(); @@ -124,7 +119,7 @@ class Session $sPrevKey = $sKey; } } - if (!self::$bSessionStarted) { + if (session_status() !== PHP_SESSION_ACTIVE) { self::Start(); unset($sSessionVar[$sKey]); $_SESSION = $aSession; @@ -191,14 +186,6 @@ class Session return array_keys($_SESSION); } - /** - * @return bool - */ - public static function IsInitialized(): bool - { - return self::$bIsInitialized; - } - /** * @return bool|string */ @@ -207,13 +194,8 @@ class Session return print_r($_SESSION, true); } - private static function IsModeCLI(): bool + public static function IsInitialized(): bool { - if (self::$bAllowCLI) { - - return false; - } - - return utils::IsModeCLI(); + return session_status() === PHP_SESSION_ACTIVE || headers_sent(); } } diff --git a/sources/Application/TwigBase/Controller/Controller.php b/sources/Application/TwigBase/Controller/Controller.php index 7c8d87c46e..d60e6e518e 100644 --- a/sources/Application/TwigBase/Controller/Controller.php +++ b/sources/Application/TwigBase/Controller/Controller.php @@ -127,6 +127,7 @@ abstract class Controller extends AbstractController */ public function __construct($sViewPath = '', $sModuleName = 'core', $aAdditionalPaths = [], array $aThemes = ['application/forms/itop_console_layout.html.twig', 'application/forms/wip_form_demonstrator.html.twig']) { + IssueLog::Enable(APPROOT.'log/error.log'); $this->aLinkedScripts = []; $this->aLinkedStylesheets = []; $this->aSaas = []; diff --git a/sources/Application/UI/Base/Component/Badge/Badge.php b/sources/Application/UI/Base/Component/Badge/Badge.php new file mode 100644 index 0000000000..9ccddb0f90 --- /dev/null +++ b/sources/Application/UI/Base/Component/Badge/Badge.php @@ -0,0 +1,103 @@ +sLabel = $sLabel; + $this->sColor = $sColor; + $this->sTooltip = $sTooltip; + } + + /** + * @return string + */ + public function GetTooltip(): string + { + return $this->sTooltip; + } + + /** + * @param string $sTooltip + */ + public function SetTooltip(string $sTooltip) + { + $this->sTooltip = $sTooltip; + return $this; + } + + /** + * @return string + */ + public function GetLabel(): string + { + return $this->sLabel; + } + + /** + * @param string $sLabel + * + * @return $this + */ + public function SetLabel(string $sLabel) + { + $this->sLabel = $sLabel; + return $this; + } + + /** + * @return string + */ + public function GetColor(): string + { + return $this->sColor; + } + + /** + * @param string $sColor + * + * @return $this + */ + public function SetColor(string $sColor) + { + $this->sColor = $sColor; + return $this; + } +} diff --git a/sources/Application/UI/Base/Component/Badge/BadgeUIBlockFactory.php b/sources/Application/UI/Base/Component/Badge/BadgeUIBlockFactory.php new file mode 100644 index 0000000000..4bf6c98785 --- /dev/null +++ b/sources/Application/UI/Base/Component/Badge/BadgeUIBlockFactory.php @@ -0,0 +1,41 @@ +sEncType = $sEncType; + return $this; + } + + /** +* @return string + * @since 3.3.0 + */ + public function GetEncType(): string + { + return $this->sEncType; + } + } diff --git a/sources/Application/UI/Base/Layout/Extension/ExtensionDetails.php b/sources/Application/UI/Base/Layout/Extension/ExtensionDetails.php new file mode 100644 index 0000000000..bf53a364c9 --- /dev/null +++ b/sources/Application/UI/Base/Layout/Extension/ExtensionDetails.php @@ -0,0 +1,228 @@ +sCode = $sCode; + $this->sLabel = $sLabel; + $this->sDescription = $sDescription; + $this->aMetaData = array_filter($aMetaData); + $this->aBadges = $aBadges; + $this->sAbout = $sAbout; + $this->InitializeToggler(); + $this->InitializePopoverMenu(); + } + + public function GetSubBlocks(): array + { + $aSubBlocks = [ + $this->oToggler->GetId() => $this->oToggler, + $this->oMoreActions->GetId() => $this->oMoreActions, + ]; + foreach ($this->aBadges as $oBadge) { + $aSubBlocks[$oBadge->GetId()] = $oBadge; + } + return $aSubBlocks; + } + + /** + * @return string + */ + public function GetCode(): string + { + return $this->sCode; + } + + /** + * @param string $sCode + * + * @return ExtensionDetails + */ + public function SetCode(string $sCode): static + { + $this->sCode = $sCode; + return $this; + } + + /** + * @return string + */ + public function GetLabel(): string + { + return $this->sLabel; + } + + /** + * @param string $sLabel + * + * @return ExtensionDetails + */ + public function SetLabel(string $sLabel): static + { + $this->sLabel = $sLabel; + return $this; + } + + /** + * @return array + */ + public function GetMetaData(): array + { + return $this->aMetaData; + } + + /** + * @param array $aMetaData + * + * @return ExtensionDetails + */ + public function SetMetaData(array $aMetaData): static + { + $this->aMetaData = array_filter($aMetaData); + return $this; + } + + /** + * @return string + */ + public function GetDescription(): string + { + return $this->sDescription; + } + + /** + * @param string $sDescription + * + * @return ExtensionDetails + */ + public function SetDescription(string $sDescription): static + { + $this->sDescription = $sDescription; + return $this; + } + + /** + * @return Toggler + */ + public function GetToggler(): Toggler + { + return $this->oToggler; + } + + /** + * @param Toggler $oToggler + * + * @return ExtensionDetails + */ + public function SetToggler(Toggler $oToggler): static + { + $this->oToggler = $oToggler; + return $this; + } + + /** + * @return array + */ + public function GetBadges(): array + { + return $this->aBadges; + } + + /** + * @param array $aBadges + * + * @return ExtensionDetails + */ + public function SetBadges(array $aBadges): static + { + $this->aBadges = $aBadges; + return $this; + } + + public function AddBadge(Badge $oBadge): static + { + $this->aBadges[] = $oBadge; + return $this; + } + + public function GetMoreActions(): UIContentBlock + { + return $this->oMoreActions; + } + + protected function InitializeToggler() + { + $sName = 'aSelectedExtensions['.$this->GetCode().']'; + $this->oToggler = new Toggler(); + $this->oToggler->SetName($sName); + $this->oToggler->AddCSSClass('toggler-install'); + } + + protected function InitializePopoverMenu() + { + $this->oPopoverMenu = new PopoverMenu(); + $oPopoverOpenButton = ButtonUIBlockFactory::MakeIconAction('fas fa-ellipsis-v', Dict::S('UI:Layout:ExtensionsDetails:MoreActions')); + $this->oPopoverMenu->SetTogglerFromBlock($oPopoverOpenButton); + $this->oMoreActions = new UIContentBlock(); + $this->oMoreActions->AddSubBlock($this->oPopoverMenu); + $this->oMoreActions->AddSubBlock($oPopoverOpenButton); + + if (mb_strlen($this->sAbout) > 0) { + $sModalLabel = Dict::Format('UI:Layout:ExtensionsDetails:MenuAboutTitle', $this->sLabel); + $sModalText = $this->sAbout; + $oModifyButton = new JSButtonItem( + 'extension_details', + Dict::S('UI:Layout:ExtensionsDetails:MenuAbout'), + <<oPopoverMenu->AddItem('more-details', PopoverMenuItemFactory::MakeFromApplicationPopupMenuItem($oModifyButton)); + } + + } + + public function AllowForceUninstall() + { + $oForceUninstallButton = new JSButtonItem( + 'force_uninstall', + Dict::S('UI:Layout:ExtensionsDetails:MenuForce'), + <<oPopoverMenu->AddItem('force-uninstall', PopoverMenuItemFactory::MakeFromApplicationPopupMenuItem($oForceUninstallButton)); + } + +} diff --git a/sources/Application/UI/Base/Layout/Extension/ExtensionDetailsUIBlockFactory.php b/sources/Application/UI/Base/Layout/Extension/ExtensionDetailsUIBlockFactory.php new file mode 100644 index 0000000000..7a1934f019 --- /dev/null +++ b/sources/Application/UI/Base/Layout/Extension/ExtensionDetailsUIBlockFactory.php @@ -0,0 +1,88 @@ +AddCSSClass('checked'); + $aBadges[] = $oBadgeInstalled; + $oBadgeToBeUninstalled = BadgeUIBlockFactory::MakeRed(Dict::S('UI:Layout:ExtensionsDetails:BadgeToBeUninstalled')); + $oBadgeToBeUninstalled->AddCSSClass('unchecked'); + $aBadges[] = $oBadgeToBeUninstalled; + + $oExtensionDetails = new ExtensionDetails($sCode, $sLabel, $sDescription, $aMetaData, $aBadges, $sAbout); + $oExtensionDetails->GetToggler()->SetIsToggled(true); + if ($bMissingFromDisk) { + $oExtensionDetails->GetToggler()->SetIsToggled(false); + $oExtensionDetails->GetToggler()->SetIsDisabled(true); + } elseif ((!$bUninstallable || $bRemote) && !$bDisabled) { + $oExtensionDetails->AllowForceUninstall(); + $oExtensionDetails->GetToggler()->SetIsDisabled(true); + } + + if (!$bSelected) { + $oExtensionDetails->GetToggler()->SetIsToggled(false); + } + if ($bDisabled) { + $oExtensionDetails->GetToggler()->SetIsDisabled(true); + $oExtensionDetails->GetToggler()->AddCSSClass('ibo-is-hidden'); + } + + return $oExtensionDetails; + } + + public static function MakeNotInstalled(string $sCode, string $sLabel, string $sDescription = '', array $aMetaData = [], array $aExtraFlags = [], string $sAbout = '') + { + $aBadges = []; + $bUninstallable = $aExtraFlags['uninstallable'] ?? true; + $bSelected = $aExtraFlags['selected'] ?? false; + $bDisabled = $aExtraFlags['disabled'] ?? false; + self::AddExtraBadges($aBadges, $bUninstallable, false); + $oBadgeInstalled = BadgeUIBlockFactory::MakeGrey(Dict::S('UI:Layout:ExtensionsDetails:BadgeNotInstalled')); + $oBadgeInstalled->AddCSSClass('unchecked'); + $aBadges[] = $oBadgeInstalled; + $oBadgeToBeUninstalled = BadgeUIBlockFactory::MakeCyan(Dict::S('UI:Layout:ExtensionsDetails:BadgeToBeInstalled')); + $oBadgeToBeUninstalled->AddCSSClass('checked'); + $aBadges[] = $oBadgeToBeUninstalled; + $oExtensionDetails = new ExtensionDetails($sCode, $sLabel, $sDescription, $aMetaData, $aBadges, $sAbout); + + if ($bSelected) { + $oExtensionDetails->GetToggler()->SetIsToggled(true); + } + if ($bDisabled) { + $oExtensionDetails->GetToggler()->SetIsDisabled(true); + $oExtensionDetails->GetToggler()->AddCSSClass('ibo-is-hidden'); + } + + return $oExtensionDetails; + } + + private static function AddExtraBadges(array &$aBadges, bool $bUninstallable, bool $bMissingFromDisk) + { + if (!$bUninstallable) { + $aBadges[] = BadgeUIBlockFactory::MakeOrange(Dict::S('UI:Layout:ExtensionsDetails:BadgeNotUninstallable')); + } + if ($bMissingFromDisk) { + $aBadges[] = BadgeUIBlockFactory::MakeRed(Dict::S('UI:Layout:ExtensionsDetails:BadgeMissingFromDisk')); + } + } +} diff --git a/sources/Application/WebPage/JsonPage.php b/sources/Application/WebPage/JsonPage.php index 4f8895a818..15da52b65b 100644 --- a/sources/Application/WebPage/JsonPage.php +++ b/sources/Application/WebPage/JsonPage.php @@ -25,6 +25,7 @@ class JsonPage extends WebPage * This can be useful when feeding response to a third party lib that doesn't understand the structured format. */ protected $bOutputDataOnly = false; + protected $bOutputHeaders = true; /** * JsonPage constructor. @@ -82,6 +83,19 @@ class JsonPage extends WebPage return $this; } + /** + * @see static::$bOutputHeaders + * @param bool $bFlag + * + * @return $this + */ + public function SetOutputHeaders(bool $bFlag) + { + $this->bOutputHeaders = $bFlag; + + return $this; + } + /** * Output the headers * @@ -119,7 +133,10 @@ class JsonPage extends WebPage public function output() { $oKpi = new ExecutionKPI(); - $this->OutputHeaders(); + if ($this->bOutputHeaders) { + $this->OutputHeaders(); + } + $sContent = $this->ComputeContent(); $oKpi->ComputeAndReport(get_class($this).' output'); diff --git a/sources/Application/WebPage/WebPage.php b/sources/Application/WebPage/WebPage.php index a5733efe35..cc47249ebc 100644 --- a/sources/Application/WebPage/WebPage.php +++ b/sources/Application/WebPage/WebPage.php @@ -21,8 +21,8 @@ use Combodo\iTop\Application\UI\Base\Layout\iUIContentBlock; use Combodo\iTop\Application\UI\Base\Layout\UIContentBlock; use Combodo\iTop\Renderer\BlockRenderer; use Combodo\iTop\Renderer\Console\ConsoleBlockRenderer; +use ContextTag; use DBSearch; -use DeprecatedCallsLog; use Dict; use ExecutionKPI; use IssueLog; @@ -1814,7 +1814,7 @@ JS; } } if ((count($this->a_dict_entries) > 0) || (count($this->a_dict_entries_prefixes) > 0)) { - if (class_exists('Dict')) { + if (class_exists('Dict') && !ContextTag::Check(ContextTag::TAG_SETUP)) { // The dictionary may not be available for example during the setup... // Create a specific dictionary file and load it as a JS script $sSignature = $this->get_dict_signature(); diff --git a/sources/Controller/AjaxRenderController.php b/sources/Controller/AjaxRenderController.php index c672cd4524..f4538713a1 100644 --- a/sources/Controller/AjaxRenderController.php +++ b/sources/Controller/AjaxRenderController.php @@ -1037,10 +1037,10 @@ EOF if ($sModuleId == '_Root_') { continue; } - if ($aModuleData['version_db'] == '') { + if ($aModuleData['installed_version'] == '') { continue; } - $oPage->add('InstalledModule/'.$sModuleId.': '.$aModuleData['version_db']."\n"); + $oPage->add('InstalledModule/'.$sModuleId.': '.$aModuleData['installed_version']."\n"); } $oPage->add('===== end ====='); diff --git a/sources/Core/AttributeDefinition/AttributeSet.php b/sources/Core/AttributeDefinition/AttributeSet.php index f70e82d731..decc13659c 100644 --- a/sources/Core/AttributeDefinition/AttributeSet.php +++ b/sources/Core/AttributeDefinition/AttributeSet.php @@ -213,7 +213,7 @@ abstract class AttributeSet extends AttributeDBFieldVoid * force an allowed value (type conversion and possibly forces a value as mySQL would do upon writing! * * @param $proposedValue - * @param DBObject $oHostObj + * @param DBObject|null $oHostObj * * @param bool $bIgnoreErrors * diff --git a/sources/Core/AttributeDefinition/AttributeTagSet.php b/sources/Core/AttributeDefinition/AttributeTagSet.php index 1e4ed3c5f6..5bc46727d2 100644 --- a/sources/Core/AttributeDefinition/AttributeTagSet.php +++ b/sources/Core/AttributeDefinition/AttributeTagSet.php @@ -7,6 +7,8 @@ namespace Combodo\iTop\Core\AttributeDefinition; +use ApplicationContext; +use cmdbAbstractObject; use CoreException; use CoreUnexpectedValue; use CoreWarning; @@ -534,21 +536,21 @@ HTML; } /** - * @param $value + * @param $sValue * @param DBObject $oHostObject * @param bool $bLocalize * * @return string * */ - public function GetAsXML($value, $oHostObject = null, $bLocalize = true) + public function GetAsXML($sValue, $oHostObject = null, $bLocalize = true) { - if (is_object($value) && ($value instanceof ormTagSet)) { + if (is_object($sValue) && ($sValue instanceof ormTagSet)) { $sRes = "\n"; if ($bLocalize) { - $aValues = $value->GetLabels(); + $aValues = $sValue->GetLabels(); } else { - $aValues = $value->GetValues(); + $aValues = $sValue->GetValues(); } if (!empty($aValues)) { $sRes .= ''.implode('', $aValues).''; @@ -636,7 +638,7 @@ HTML; public function FromJSONToValue($json) { $oSet = new ormTagSet($this->GetHostClass(), $this->GetCode(), $this->GetMaxItems()); - $oSet->SetValues($json); + $oSet->SetValues(json_decode($json, true)); return $oSet; } diff --git a/sources/Service/InterfaceDiscovery/InterfaceDiscovery.php b/sources/Service/InterfaceDiscovery/InterfaceDiscovery.php index 67a5ca2fa4..d21f6bcfd6 100644 --- a/sources/Service/InterfaceDiscovery/InterfaceDiscovery.php +++ b/sources/Service/InterfaceDiscovery/InterfaceDiscovery.php @@ -178,12 +178,19 @@ class InterfaceDiscovery continue; } $aTmpClassMap = include $sAutoloadFile; + if (! is_array($aTmpClassMap)) { + //can happen when setup compilation broken in the middle + //ex: $sAutoloadFile could be empty and $aTmpClassMap is a int + $aAutoloaderErrors[] = $sAutoloadFile; + continue; + } + /** @noinspection SlowArrayOperationsInLoopInspection we are getting an associative array so the documented workarounds cannot be used */ $aClassMap = array_merge($aClassMap, $aTmpClassMap); } if (count($aAutoloaderErrors) > 0) { IssueLog::Debug( - __METHOD__." cannot load some of the autoloader files", + __METHOD__." cannot load some of the autoloader files: missing or corrupted", LogChannels::CORE, ['autoloader_errors' => $aAutoloaderErrors] ); diff --git a/sources/Service/Limits/ExecutionLimits.php b/sources/Service/Limits/ExecutionLimits.php new file mode 100644 index 0000000000..14af39a707 --- /dev/null +++ b/sources/Service/Limits/ExecutionLimits.php @@ -0,0 +1,47 @@ +iMaxTime = ($iMaxDuration > 0) ? ($iMaxDuration + time()) : 0; + $this->iMaxMemoryPercent = (int)min(max($iMaxMemoryPercent, 0), 100); + } + /** + * @return bool true when duration is + */ + public function ShouldStopExecution(): bool + { + if (($this->iMaxTime != 0) && (time() > $this->iMaxTime)) { + \IssueLog::Debug(__METHOD__.' timeout '.time()." (current) > $this->iMaxTime (max)"); + return true; + } + + $iMaxMemoryPercent = (int)min(max($this->iMaxMemoryPercent, 0), 100); + $iMemory = memory_get_usage(true); + $iMaxMemory = utils::GetMemoryLimit() * $iMaxMemoryPercent / 100; + if ($iMemory > $iMaxMemory) { + \IssueLog::Debug(__METHOD__." Memory limit $iMemory (current) > $iMaxMemory (max)"); + return true; + } + + return false; + } + +} diff --git a/templates/base/components/badge/layout.html.twig b/templates/base/components/badge/layout.html.twig new file mode 100644 index 0000000000..1af345263a --- /dev/null +++ b/templates/base/components/badge/layout.html.twig @@ -0,0 +1,8 @@ + + {{ oUIBlock.GetLabel() }} + \ No newline at end of file diff --git a/templates/base/components/form/layout.html.twig b/templates/base/components/form/layout.html.twig index 756dee0924..7b2808e7ce 100644 --- a/templates/base/components/form/layout.html.twig +++ b/templates/base/components/form/layout.html.twig @@ -1,4 +1,4 @@ -
    - {{ parent() }} + {{ parent() }} + {% endblock %} diff --git a/templates/base/components/input/input-toggler.ready.js.twig b/templates/base/components/input/input-toggler.ready.js.twig index d3fdecc0fe..703c0c5ad9 100644 --- a/templates/base/components/input/input-toggler.ready.js.twig +++ b/templates/base/components/input/input-toggler.ready.js.twig @@ -1,5 +1,10 @@ + $('#{{ oUIBlock.GetId() }}').parent().on('click', function() { - let oInput = $(this).find('.ibo-toggler'); - oInput.prop('checked', !oInput.prop('checked')); - oInput.trigger('change'); + let oInput = $(this).find('.ibo-toggler'); + let oHiddenInput = $(this).find('.ibo-toggler--hidden'); + if (!oInput.prop('disabled')) { + oInput.prop('checked', !oInput.prop('checked')); + oHiddenInput.val(oInput.prop('checked') ? 'on' : 'off'); + oInput.trigger('change'); + } }); \ No newline at end of file diff --git a/templates/base/layouts/extension/extension-details/layout.html.twig b/templates/base/layouts/extension/extension-details/layout.html.twig new file mode 100644 index 0000000000..15639cf39e --- /dev/null +++ b/templates/base/layouts/extension/extension-details/layout.html.twig @@ -0,0 +1,24 @@ +{# @copyright Copyright (C) 2010-2024 Combodo SAS #} +{# @license http://opensource.org/licenses/AGPL-3.0 #} +
    +
    +
    + {{ oUIBlock.GetLabel() }} + {% for oBadge in oUIBlock.GetBadges() %} + {{ render_block(oBadge, {aPage: aPage}) }} + {% endfor %} +
    + +
    + {{ oUIBlock.GetDescription() }} +
    +
    +
    + {{ render_block(oUIBlock.GetToggler(), {aPage: aPage}) }} + {{ render_block(oUIBlock.GetMoreActions(), {aPage: aPage}) }} +
    +
    \ No newline at end of file diff --git a/tests/manual-visual-tests/Backoffice/RenderAllUiBlocks.php b/tests/manual-visual-tests/Backoffice/RenderAllUiBlocks.php index fa4027813f..a1bb135d05 100644 --- a/tests/manual-visual-tests/Backoffice/RenderAllUiBlocks.php +++ b/tests/manual-visual-tests/Backoffice/RenderAllUiBlocks.php @@ -24,6 +24,8 @@ namespace Combodo\iTop\Test\VisualTest\Backoffice; use Combodo\iTop\Application\Branding; use Combodo\iTop\Application\UI\Base\Component\Alert\AlertUIBlockFactory; +use Combodo\iTop\Application\UI\Base\Component\Badge\Badge; +use Combodo\iTop\Application\UI\Base\Component\Badge\BadgeUIBlockFactory; use Combodo\iTop\Application\UI\Base\Component\Button\Button; use Combodo\iTop\Application\UI\Base\Component\Button\ButtonUIBlockFactory; use Combodo\iTop\Application\UI\Base\Component\ButtonGroup\ButtonGroup; @@ -35,16 +37,23 @@ use Combodo\iTop\Application\UI\Base\Component\FieldSet\FieldSet; use Combodo\iTop\Application\UI\Base\Component\Html\Html; use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory; use Combodo\iTop\Application\UI\Base\Component\Input\Set\SetUIBlockFactory; +use Combodo\iTop\Application\UI\Base\Component\Input\Toggler; use Combodo\iTop\Application\UI\Base\Component\Panel\Panel; use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory; use Combodo\iTop\Application\UI\Base\Component\Pill\PillFactory; use Combodo\iTop\Application\UI\Base\Component\PopoverMenu\PopoverMenu; +use Combodo\iTop\Application\UI\Base\Component\PopoverMenu\PopoverMenuItem\PopoverMenuItemFactory; use Combodo\iTop\Application\UI\Base\Component\Title\TitleUIBlockFactory; +use Combodo\iTop\Application\UI\Base\Layout\Extension\ExtensionDetails; +use Combodo\iTop\Application\UI\Base\Layout\Extension\ExtensionDetailsUIBlockFactory; +use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\Column\Column; +use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\MultiColumn; use Combodo\iTop\Application\UI\Base\Layout\Object\ObjectFactory; use Combodo\iTop\Application\UI\Base\Layout\PageContent\PageContentFactory; use Combodo\iTop\Application\UI\Base\Layout\UIContentBlockUIBlockFactory; use Combodo\iTop\Application\UI\Base\Layout\UIContentBlockWithJSRefreshCallback; use Combodo\iTop\Application\WebPage\iTopWebPage; +use JSButtonItem; use LoginWebPage; use MetaModel; @@ -69,7 +78,7 @@ $oMainTitle = new Html('

    All UI blocks examples

    '); $oPage->AddUiBlock($oMainTitle); $oPageContentLayout->AddMainBlock(new Html('
    ')); - +$oPage->add('Go to bottom of the page'); ///////// // Alerts ///////// @@ -581,4 +590,60 @@ $oPage->AddUiBlock($oSimpleSetBlockOql); $oSimpleSetBlockOql2 = SetUIBlockFactory::MakeForOQL('SetOql2', 'Location', 'SELECT Location', null, [], null, 'OqlSet2'); $oPage->AddUiBlock($oSimpleSetBlockOql2); +$oPage->AddUiBlock(TitleUIBlockFactory::MakeNeutral('Toggler', 3)); + +$oToggler = new Toggler(); +$oToggler->SetName('SampleToggler'); +$oPage->AddUiBlock($oToggler); + +$oTogglerActivated = new Toggler(); +$oTogglerActivated->SetName('SampleTogglerActivated'); +$oTogglerActivated->SetIsToggled(true); +$oPage->AddUiBlock($oTogglerActivated); + +$oTogglerDisabled = new Toggler(); +$oTogglerDisabled->SetName('SampleTogglerDisabled'); +$oTogglerDisabled->SetIsDisabled(true); +$oPage->AddUiBlock($oTogglerDisabled); + +$oTogglerActivatedDisabled = new Toggler(); +$oTogglerActivatedDisabled->SetName('SampleTogglerDisabled'); +$oTogglerActivatedDisabled->SetIsToggled(true); +$oTogglerActivatedDisabled->SetIsDisabled(true); +$oPage->AddUiBlock($oTogglerActivatedDisabled); + +$oPage->AddUiBlock(TitleUIBlockFactory::MakeNeutral('Badges', 3)); + +$oSampleBadgeNeutral = BadgeUIBlockFactory::MakeNeutral('badge neutral', 'Tooltip'); +$oPage->AddUiBlock($oSampleBadgeNeutral); +$oSampleBadgeCyan = BadgeUIBlockFactory::MakeCyan('badge cyan', 'Tooltip'); +$oPage->AddUiBlock($oSampleBadgeCyan); +$oSampleBadgeGreen = BadgeUIBlockFactory::MakeGreen('badge green', 'Tooltip'); +$oPage->AddUiBlock($oSampleBadgeGreen); +$oSampleBadgeGrey = BadgeUIBlockFactory::MakeGrey('badge grey', 'Tooltip'); +$oPage->AddUiBlock($oSampleBadgeGrey); +$oSampleBadgeOrange = BadgeUIBlockFactory::MakeOrange('badge orange', 'Tooltip'); +$oPage->AddUiBlock($oSampleBadgeOrange); +$oSampleBadgeRed = BadgeUIBlockFactory::MakeRed('badge red', 'Tooltip'); +$oPage->AddUiBlock($oSampleBadgeRed); + +$oPage->AddUiBlock(TitleUIBlockFactory::MakeNeutral('Extensions details layout', 3)); + +$oMultiCol = new MultiColumn(); +$oColumnLeft = new Column(); +$oColumnRight = new Column(); +$oMultiCol->AddColumn($oColumnLeft); +$oMultiCol->AddColumn($oColumnRight); +$oPage->AddUiBlock($oMultiCol); + +$oExtensionDetailInstalledFromFactory = ExtensionDetailsUIBlockFactory::MakeInstalled('itop-sample', 'My extension v2', 'This is for test only', ['v1.1.1', 'Designer', '12/12/2012'], ['uninstallable' => false,'missing' => true]); +$oColumnLeft->AddSubBlock($oExtensionDetailInstalledFromFactory); + +$oExtensionDetailInstalledFromFactory = ExtensionDetailsUIBlockFactory::MakeInstalled('itop-not-uninstallable', 'You cannot uninstall me', 'Click force uninstall to uninstall me', ['v9.9.9', 'Void', '12/12/2012'], ['uninstallable' => false,'missing' => false]); +$oColumnLeft->AddSubBlock($oExtensionDetailInstalledFromFactory); + +$oExtensionDetailInstalledWithLongTitle = ExtensionDetailsUIBlockFactory::MakeNotInstalled('itop-sample', 'My extension with a very long title', 'This is for test only', ['v1.1.1', 'Designer', '12/12/2012'], ['uninstallable' => false]); +$oColumnRight->AddSubBlock($oExtensionDetailInstalledWithLongTitle); +$oPage->add('
    '); + $oPage->output(); diff --git a/tests/php-static-analysis/config/base.dist.neon b/tests/php-static-analysis/config/base.dist.neon index eaf30b8725..e1ac3d09c2 100644 --- a/tests/php-static-analysis/config/base.dist.neon +++ b/tests/php-static-analysis/config/base.dist.neon @@ -1,7 +1,7 @@ includes: - php-includes/set-php-version-from-process.php # Workaround to set PHP version to the on running the CLI # for an explanation of the baseline concept, see: https://phpstan.org/user-guide/baseline - #baseline HERE DO NOT REMOVE FOR CI + #baseline HERE DO NOT REMOVE FOR CI parameters: level: 0 @@ -36,5 +36,6 @@ parameters: - ../../../env-php-unit-tests (?) # Irrelevant as it will either already be in `env-production` or might be desynchronized from `env-production` - ../../../env-toolkit (?) # Irrelevent as it will either already be in `env-production` or might be desynchronized from `env-production` (for local run only, not useful in the CI) - - ../../../tests (?) # Exclude tests for now - - ../../../toolkit (?) # Exlclude toolkit for now + #- ../../../tests (?) # Exclude tests for now + - ../../../toolkit (?) # Exclude toolkit for now + - ../../../setup/compat # Exclude fake DOMDocument & DOMElement declarations diff --git a/tests/php-unit-tests/integration-tests/itop-hub-connector/HubControllerTest.php b/tests/php-unit-tests/integration-tests/itop-hub-connector/HubControllerTest.php new file mode 100644 index 0000000000..7e1a1580ee --- /dev/null +++ b/tests/php-unit-tests/integration-tests/itop-hub-connector/HubControllerTest.php @@ -0,0 +1,80 @@ +SkipIfModuleNotPresent('itop-hub-connector'); + parent::setUp(); + $this->RequireOnceItopFile('env-production/itop-hub-connector/src/Controller/HubController.php'); + } + + public function testLaunchCompile(): void + { + $this->PrepareCompileAuthent(); + + $this->CopyProductionModulesIntoHubExtensionDir(); + + HubController::GetInstance()->SetOutputHeaders(false); + + HubController::GetInstance()->LaunchCompile(); + + $this->CheckReport('{"code":0,"message":"Ok","fields":[]}'); + } + + public function testLaunchDeploy(): void + { + $this->testLaunchCompile(); + HubController::GetInstance()->LaunchDeploy(); + $this->CheckReport('{"code":0,"message":"Compilation successful.","fields":[]}'); + $this->AssertPreviousAndCurrentInstallationAreEquivalent(); + } + + private function CheckReport($sExpected) + { + $oJsonPage = HubController::GetInstance()->GetLastJsonPage(); + $this->assertEquals($sExpected, $this->InvokeNonPublicMethod(JsonPage::class, 'ComputeContent', $oJsonPage, [])); + + //keep line below to avoid: Test code or tested code did not (only) close its own output buffers + $this->InvokeNonPublicMethod(JsonPage::class, 'RenderContent', $oJsonPage, []); + } + + private function PrepareCompileAuthent() + { + $sUUID = 'hub_'.uniqid(); + $_REQUEST['authent'] = $sUUID; + $sPath = utils::GetDataPath().'hub/compile_authent'; + file_put_contents($sPath, $sUUID); + $this->aFileToClean[] = $sPath; + } + + private function CopyProductionModulesIntoHubExtensionDir() + { + $sProdModules = APPROOT.'/data/production-modules'; + $sExtensionDir = APPROOT.'/data/downloaded-extensions/'; + $this->aFileToClean[] = $sExtensionDir; + + SetupUtils::rrmdir($sExtensionDir); + @mkdir($sExtensionDir); + SetupUtils::copydir($sExtensionDir, $sProdModules); + } +} diff --git a/tests/php-unit-tests/src/BaseTestCase/ItopCustomDatamodelTestCase.php b/tests/php-unit-tests/src/BaseTestCase/ItopCustomDatamodelTestCase.php index bb3421ebc5..7034cb5b5a 100644 --- a/tests/php-unit-tests/src/BaseTestCase/ItopCustomDatamodelTestCase.php +++ b/tests/php-unit-tests/src/BaseTestCase/ItopCustomDatamodelTestCase.php @@ -54,10 +54,20 @@ abstract class ItopCustomDatamodelTestCase extends ItopDataTestCase */ abstract public function GetDatamodelDeltaAbsPath(): string; + /** + * @return array : dict extensions folders by their code + */ + public function GetAdditionalFeaturePaths(): array + { + return []; + } + protected function setUp(): void { static::LoadRequiredItopFiles(); - $this->oEnvironment = new UnitTestRunTimeEnvironment('production', $this->GetTestEnvironment()); + if (is_null($this->oEnvironment)) { + $this->oEnvironment = new UnitTestRunTimeEnvironment($this->GetTestEnvironment()); + } parent::setUp(); } @@ -123,7 +133,6 @@ abstract class ItopCustomDatamodelTestCase extends ItopDataTestCase // Note: To improve performances, we compile all XML deltas from test cases derived from this class and make a single environment where everything will be ran at once. // This requires XML deltas to be compatible, but it is a known and accepted trade-off. See PR #457 if (false === $this->IsEnvironmentReady()) { - $this->debug("Preparing custom environment '$sTestEnv' with the following datamodel files:"); foreach ($this->oEnvironment->GetCustomDatamodelFiles() as $sCustomDatamodelFile) { $this->debug(" - $sCustomDatamodelFile"); @@ -155,24 +164,36 @@ abstract class ItopCustomDatamodelTestCase extends ItopDataTestCase $oTestConfig->ChangeModulesPath($sSourceEnv, $sTestEnv); // - Switch DB name to a dedicated one so we don't mess with the original one $sTestEnvSanitizedForDBName = preg_replace('/[^\d\w]/', '', $sTestEnv); - $oTestConfig->Set('db_name', $oTestConfig->Get('db_name').'_'.$sTestEnvSanitizedForDBName); + $sPreviousDB = $oTestConfig->Get('db_name'); + $sNewDB = $sPreviousDB.'_'.$sTestEnvSanitizedForDBName; + $oTestConfig->Set('db_name', $sNewDB); // - Compile env. based on the existing 'production' env. - $oEnvironment = new UnitTestRunTimeEnvironment($sSourceEnv, $sTestEnv); - $oEnvironment->WriteConfigFileSafe($oTestConfig); - $oEnvironment->CompileFrom($sSourceEnv); + //$oEnvironment = new UnitTestRunTimeEnvironment($sSourceEnv, $sTestEnv); + $this->oEnvironment->WriteConfigFileSafe($oTestConfig); + $this->oEnvironment->CompileFrom($sSourceEnv); // - Force re-creating a fresh DB CMDBSource::InitFromConfig($oTestConfig); - if (CMDBSource::IsDB($oTestConfig->Get('db_name'))) { + if (CMDBSource::IsDB($sNewDB)) { CMDBSource::DropDB(); } - CMDBSource::CreateDB($oTestConfig->Get('db_name')); + CMDBSource::CreateDB($sNewDB); MetaModel::Startup($sConfFile, false /* $bModelOnly */, true /* $bAllowCache */, false /* $bTraceSourceFiles */, $sTestEnv); // N°7446 For some reason we need to create the DB schema before starting the MM, then only we can create the tables. MetaModel::DBCreate(); + // Make sure that runtime environment is complete + // RunTimeEnvironment::AnalyzeInstallation would not return core modules otherwise... + CMDBSource::DropTable("priv_module_install"); + CMDBSource::Query("CREATE TABLE $sNewDB.priv_module_install SELECT * FROM $sPreviousDB.priv_module_install"); + + CMDBSource::DropTable("priv_extension_install"); + CMDBSource::Query("CREATE TABLE $sNewDB.priv_extension_install SELECT * FROM $sPreviousDB.priv_extension_install"); + $this->debug("Custom environment '$sTestEnv' is ready!"); + } else { + $this->debug("Custom environment '$sTestEnv' READY BUILT:"); } parent::PrepareEnvironment(); diff --git a/tests/php-unit-tests/src/BaseTestCase/ItopDataTestCase.php b/tests/php-unit-tests/src/BaseTestCase/ItopDataTestCase.php index 508fb3d2b4..7be4d9d6be 100644 --- a/tests/php-unit-tests/src/BaseTestCase/ItopDataTestCase.php +++ b/tests/php-unit-tests/src/BaseTestCase/ItopDataTestCase.php @@ -34,6 +34,7 @@ use lnkContactToTicket; use lnkFunctionalCIToTicket; use MetaModel; use MissingQueryArgument; +use ModuleInstallationRepository; use MySQLException; use MySQLHasGoneAwayException; use Person; @@ -1446,27 +1447,48 @@ abstract class ItopDataTestCase extends ItopTestCase return $sLogin; } + protected function GivenUserWithContactInDB(string $sLogin, string $sProfileId, string $sPassword, string $sPersonId, string $sOrgId): string + { + return $this->GivenObjectInDB('UserLocal', [ + 'login' => $sLogin, + 'password' => $sPassword, + 'language' => 'EN US', + 'profile_list' => [ + 'profileid:'.self::$aURP_Profiles[$sProfileId], + ], + 'contactid' => $sPersonId, + 'allowed_org_list' => [ + 'allowed_org_id:'.$sOrgId, + ], + ]); + } + /** * @param string $sPassword * @param array $aProfiles Profile names Example: ['Administrator'] + * @param string|null $sLogin + * @param string|null $sUserId * * @return string The unique login * @throws \Exception */ - protected function GivenUserInDB(string $sPassword, array $aProfiles): string + protected function GivenUserInDB(string $sPassword, array $aProfiles, ?string $sLogin = null, ?string &$sUserId = null): string { - $sLogin = 'demo_test_'.uniqid(__CLASS__, true); + if (is_null($sLogin)) { + $sLogin = 'demo_test_'.uniqid(__CLASS__, true); + } $aProfileList = array_map(function ($sProfileId) { return 'profileid:'.self::$aURP_Profiles[$sProfileId]; }, $aProfiles); - $iUser = $this->GivenObjectInDB('UserLocal', [ + $sUserId = $this->GivenObjectInDB('UserLocal', [ 'login' => $sLogin, 'password' => $sPassword, 'language' => 'EN US', 'profile_list' => $aProfileList, ]); + return $sLogin; } @@ -1553,6 +1575,34 @@ abstract class ItopDataTestCase extends ItopTestCase @chmod($sConfigPath, 0440); @unlink($this->sConfigTmpBackupFile); } + + public function AssertPreviousAndCurrentInstallationAreEquivalent() + { + $aPreviousInstallations = ModuleInstallationRepository::GetInstance()->GetPreviousModuleInstallationsByOffset(1); + $aInstallations = ModuleInstallationRepository::GetInstance()->GetPreviousModuleInstallationsByOffset(); + $this->assertEquals($this->GetCanonicalComparableModuleInstallationArray($aPreviousInstallations), $this->GetCanonicalComparableModuleInstallationArray($aInstallations)); + } + + protected function GetCanonicalComparableModuleInstallationArray($aInstallations): array + { + $aRes = []; + $aIgnoredFields = ['id', 'parent_id', 'installed', 'comment']; + foreach ($aInstallations as $aData) { + $aNewData = []; + foreach ($aData as $sKey => $val) { + if (in_array($sKey, $aIgnoredFields)) { + continue; + } + $aNewData[$sKey] = $val; + } + $sName = $aNewData['name']; + $aRes[$sName] = $aNewData; + } + + asort($aRes); + return $aRes; + } + protected function AddLoginModeAndSaveConfiguration(string $sLoginMode): void { $aAllowedLoginTypes = $this->oiTopConfig->GetAllowedLoginTypes(); diff --git a/tests/php-unit-tests/src/BaseTestCase/ItopTestCase.php b/tests/php-unit-tests/src/BaseTestCase/ItopTestCase.php index 7c4ed7ba4c..393d309d16 100644 --- a/tests/php-unit-tests/src/BaseTestCase/ItopTestCase.php +++ b/tests/php-unit-tests/src/BaseTestCase/ItopTestCase.php @@ -197,6 +197,7 @@ abstract class ItopTestCase extends KernelTestCase } SetupUtils::tidydir($sPath); + SetupUtils::rrmdir($sPath); } } @@ -740,6 +741,19 @@ abstract class ItopTestCase extends KernelTestCase return $this->CallUrl($sUrl, $aPostFields, $aCurlOptions, $bXDebugEnabled); } + /** + * Return a temporary file path. that will be cleaned up by tearDown() + * + * @return string: temporary file path: file prefix include phpunit test method name + */ + public function GetTemporaryFilePath(): string + { + $sPrefix = $this->getName(false); + $sPath = tempnam(sys_get_temp_dir(), $sPrefix); + $this->aFileToClean[] = $sPath; + return $sPath; + } + /** * @param $sXML * diff --git a/tests/php-unit-tests/src/Service/UnitTestRunTimeEnvironment.php b/tests/php-unit-tests/src/Service/UnitTestRunTimeEnvironment.php index 8080d8abb6..4cd3b9d900 100644 --- a/tests/php-unit-tests/src/Service/UnitTestRunTimeEnvironment.php +++ b/tests/php-unit-tests/src/Service/UnitTestRunTimeEnvironment.php @@ -8,11 +8,13 @@ namespace Combodo\iTop\Test\UnitTest\Service; use Combodo\iTop\Test\UnitTest\ItopCustomDatamodelTestCase; +use DOMFormatException; use MFCoreModule; use RecursiveDirectoryIterator; use RecursiveIteratorIterator; use ReflectionClass; use RunTimeEnvironment; +use SetupLog; use SetupUtils; use utils; @@ -26,37 +28,51 @@ use utils; */ class UnitTestRunTimeEnvironment extends RunTimeEnvironment { + /** + * @var false + */ + public bool $bUseDelta = true; + + /** + * @var true + */ + public bool $bUseAdditionalFeatures = false; + /** * @var string[] */ protected $aCustomDatamodelFiles = null; /** - * @var string + * @var string[] */ - protected $sSourceEnv; - - public function __construct($sSourceEnv, $sTargetEnv) - { - parent::__construct($sTargetEnv); - $this->sSourceEnv = $sSourceEnv; - } - - public function GetEnvironment(): string - { - return $this->sFinalEnv; - } + protected $aAdditionExtensionFoldersByCode = null; public function CompileFrom($sSourceEnv, $bUseSymLinks = null) { - $sDestModulesDir = APPROOT.'data/'.$this->sTargetEnv.'-modules/'; + $sDestModulesDir = APPROOT.'data/'.$this->sBuildEnv.'-modules/'; if (is_dir($sDestModulesDir)) { SetupUtils::rrmdir($sDestModulesDir); } - SetupUtils::copydir(APPROOT.'/data/'.$sSourceEnv.'-modules', $sDestModulesDir, $bUseSymLinks); + SetupUtils::copydir(APPROOT.'/data/'.$sSourceEnv.'-modules', $sDestModulesDir, (true === $bUseSymLinks)); - parent::CompileFrom($sSourceEnv, $bUseSymLinks); + if ($this->bUseAdditionalFeatures) { + foreach ($this->GetExtensionFoldersToAdd() as $sExtensionCode => $sFolderPath) { + \SetupLog::Info("ExtensionFoldersToAdd: $sExtensionCode => $sFolderPath"); + $sFolderName = basename($sFolderPath); + @mkdir($sDestModulesDir.DIRECTORY_SEPARATOR.$sFolderName); + SetupUtils::copydir($sFolderPath, $sDestModulesDir.DIRECTORY_SEPARATOR.$sFolderName, (true === $bUseSymLinks)); + } + } + + try { + parent::CompileFrom($sSourceEnv, $bUseSymLinks); + } catch (DOMFormatException $e) { + $sFileName = $sSourceEnv.'.delta.xml'; + SetupLog::Error(__METHOD__, null, [$sFileName => @file_get_contents(APPROOT.'data/'.$sFileName)]); + throw $e; + } } public function IsUpToDate() @@ -94,23 +110,43 @@ class UnitTestRunTimeEnvironment extends RunTimeEnvironment */ protected function GetMFModulesToCompile($sSourceEnv, $sSourceDir) { + \SetupLog::Info(__METHOD__); $aRet = parent::GetMFModulesToCompile($sSourceEnv, $sSourceDir); - foreach ($this->GetCustomDatamodelFiles() as $sDeltaFile) { - $sDeltaId = preg_replace('/[^\d\w]/', '', $sDeltaFile); - $sDeltaName = basename($sDeltaFile); - $sDeltaDir = dirname($sDeltaFile); - $oDelta = new MFCoreModule($sDeltaName, "$sDeltaDir/$sDeltaName", $sDeltaFile); - $aRet[$sDeltaId] = $oDelta; + if ($this->bUseDelta) { + foreach ($this->GetCustomDatamodelFiles() as $sDeltaFile) { + $sDeltaId = preg_replace('/[^\d\w]/', '', $sDeltaFile); + $sDeltaName = basename($sDeltaFile); + $sDeltaDir = dirname($sDeltaFile); + $oDelta = new MFCoreModule($sDeltaName, "$sDeltaDir/$sDeltaName", $sDeltaFile); + $aRet[$sDeltaId] = $oDelta; + } } + return $aRet; } - public function GetCustomDatamodelFiles() + public function GetExtensionFoldersToAdd(): array { - if (!is_null($this->aCustomDatamodelFiles)) { - return $this->aCustomDatamodelFiles; + if (is_null($this->aAdditionExtensionFoldersByCode)) { + $this->InitViaItopCustomDatamodelTestCaseClasses(); } + + return $this->aAdditionExtensionFoldersByCode; + } + + public function GetCustomDatamodelFiles(): array + { + if (is_null($this->aCustomDatamodelFiles)) { + $this->InitViaItopCustomDatamodelTestCaseClasses(); + } + + return $this->aCustomDatamodelFiles; + } + + public function InitViaItopCustomDatamodelTestCaseClasses() + { + $this->aAdditionExtensionFoldersByCode = []; $this->aCustomDatamodelFiles = []; // Search for the PHP files implementing the method GetDatamodelDeltaAbsPath @@ -169,16 +205,19 @@ class UnitTestRunTimeEnvironment extends RunTimeEnvironment continue; } $sDeltaFile = $oTestClassInstance->GetDatamodelDeltaAbsPath(); - if (!is_file($sDeltaFile)) { - throw new \Exception("Unknown delta file: $sDeltaFile, from test class '$sClass'"); - } - if (!in_array($sDeltaFile, $this->aCustomDatamodelFiles)) { - $this->aCustomDatamodelFiles[] = $sDeltaFile; + if (strlen($sDeltaFile) > 0) { + if (!is_file($sDeltaFile)) { + throw new \Exception("Unknown delta file: $sDeltaFile, from test class '$sClass'"); + } + if (!in_array($sDeltaFile, $this->aCustomDatamodelFiles)) { + $this->aCustomDatamodelFiles[] = $sDeltaFile; + } } + + $aExtensionsPaths = $oTestClassInstance->GetAdditionalFeaturePaths(); + $this->aAdditionExtensionFoldersByCode = array_merge($this->aAdditionExtensionFoldersByCode, $aExtensionsPaths); } } - - return $this->aCustomDatamodelFiles; } private function FindFilesModifiedAfter(float $fReferenceTimestamp, string $sPathToScan, array &$aModifiedFiles) diff --git a/data/.compilation-symlinks b/tests/php-unit-tests/unitary-tests/application/LoginTest.php similarity index 100% rename from data/.compilation-symlinks rename to tests/php-unit-tests/unitary-tests/application/LoginTest.php diff --git a/tests/php-unit-tests/unitary-tests/core/DBObject/DBObjectTest.php b/tests/php-unit-tests/unitary-tests/core/DBObject/DBObjectTest.php index 2f18e7ff26..1dfb4e9aea 100644 --- a/tests/php-unit-tests/unitary-tests/core/DBObject/DBObjectTest.php +++ b/tests/php-unit-tests/unitary-tests/core/DBObject/DBObjectTest.php @@ -22,8 +22,6 @@ namespace Combodo\iTop\Test\UnitTest\Core; use Attachment; use AttributeDateTime; -use Combodo\iTop\Application\WebPage\iTopWebPage; -use Combodo\iTop\Application\WebPage\WebPage; use Combodo\iTop\Service\Events\EventData; use Combodo\iTop\Test\UnitTest\ItopDataTestCase; use CoreException; @@ -39,7 +37,6 @@ use Team; use User; use UserRequest; use UserRights; -use utils; /** * @group specificOrgInSampleData @@ -524,7 +521,7 @@ class DBObjectTest extends ItopDataTestCase $oAdminUser = MetaModel::GetObjectByName(User::class, 'admin', false); if (is_null($oAdminUser)) { - $oAdminUser = $this->CreateUser('admin', 1); + $oAdminUser = $this->CreateUser('admin', 1, 'Zydw&%&h25F4'); } /** @var Person $oPersonObject */ diff --git a/tests/php-unit-tests/unitary-tests/core/MetaModelTest.php b/tests/php-unit-tests/unitary-tests/core/MetaModelTest.php index 74c947731b..ed14c9c2b6 100644 --- a/tests/php-unit-tests/unitary-tests/core/MetaModelTest.php +++ b/tests/php-unit-tests/unitary-tests/core/MetaModelTest.php @@ -498,6 +498,34 @@ class MetaModelTest extends ItopDataTestCase 'Purge 10 items with a max_chunk_size of 1000 (default value) should be perfomed in 1 step' => [1000, 3], ]; } + + public function testGetCreatedIn_UnknownClass() + { + $this->expectExceptionMessage("Cannot find class module"); + $this->expectException(CoreException::class); + + MetaModel::GetModuleName('GABUZOMEU'); + } + + public function testGetCreatedIn_ClassComingFromCorePhpFile() + { + $this->assertEquals('core', MetaModel::GetModuleName('BackgroundTask')); + } + + public function testGetCreatedIn_ClassComingFromCorePhpFile2() + { + $this->assertEquals('core', MetaModel::GetModuleName('lnkActionNotificationToContact')); + } + + public function testGetCreatedIn_ClassComingFromModulePhpFile() + { + $this->assertEquals('itop-attachments', MetaModel::GetModuleName('CMDBChangeOpAttachmentAdded')); + } + + public function testGetCreatedIn_ClassComingFromXmlDataModelFile() + { + $this->assertEquals('authent-ldap', MetaModel::GetModuleName('UserLDAP')); + } } abstract class Wizzard diff --git a/tests/php-unit-tests/unitary-tests/datamodels/2.x/authent-local/UserLocalTest.php b/tests/php-unit-tests/unitary-tests/datamodels/2.x/authent-local/UserLocalTest.php index a02a685492..27e709baad 100644 --- a/tests/php-unit-tests/unitary-tests/datamodels/2.x/authent-local/UserLocalTest.php +++ b/tests/php-unit-tests/unitary-tests/datamodels/2.x/authent-local/UserLocalTest.php @@ -268,7 +268,7 @@ class UserLocalTest extends ItopDataTestCase $this->assertEquals($oBefore, $oUserLocal->Get('password_renewed_date')); //INSERT - $oUserLocal->Set('password', 'fooBar1???'); + $oUserLocal->Set('password', 'Zydw&%&h25F4'); $oUserLocal->DBWrite(); $this->assertEquals($oNow, $oUserLocal->Get('password_renewed_date'), 'INSERT sets the "password_renewed_date" to the current date'); @@ -280,13 +280,13 @@ class UserLocalTest extends ItopDataTestCase //UPDATE password $oUserLocal = MetaModel::GetObject(UserLocal::class, $oUserLocal->GetKey()); - $oUserLocal->Set('password', 'fooBar1???1'); + $oUserLocal->Set('password', 'Zydw&%&h25F5'); $oUserLocal->DBWrite(); $this->assertEquals($oExpectedAfter, $oUserLocal->Get('password_renewed_date'), 'UPDATE "password" fields trigger automatic change of the "password_renewed_date" field'); //UPDATE both password & password_renewed_date $oUserLocal = MetaModel::GetObject(UserLocal::class, $oUserLocal->GetKey()); - $oUserLocal->Set('password', 'fooBar1???2'); + $oUserLocal->Set('password', 'Zydw&%&h25F6'); $oUserLocal->Set('password_renewed_date', $oBefore); $oUserLocal->DBWrite(); $this->assertEquals($oBefore, $oUserLocal->Get('password_renewed_date'), 'UPDATE can target and change both "password" and "password_renewed_date"'); @@ -337,7 +337,7 @@ class UserLocalTest extends ItopDataTestCase $this->assertEquals($oBefore, $oUserLocal->Get('password_renewed_date')); //INSERT - $oUserLocal->Set('password', 'fooBar1???'); + $oUserLocal->Set('password', 'Zydw&%&h25F4'); $oUserLocal->DBWrite(); $this->assertEquals($oNow, $oUserLocal->Get('password_renewed_date'), 'INSERT sets the "password_renewed_date" to the current date'); diff --git a/tests/php-unit-tests/unitary-tests/datamodels/2.x/combodo-data-feature-removal/DataCleanupServiceTest.php b/tests/php-unit-tests/unitary-tests/datamodels/2.x/combodo-data-feature-removal/DataCleanupServiceTest.php new file mode 100644 index 0000000000..6acb5f026c --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/datamodels/2.x/combodo-data-feature-removal/DataCleanupServiceTest.php @@ -0,0 +1,306 @@ +GetCleanupSummary(null); + + $this->assertIsArray($aResult, 'Expected result to be an array when input is null.'); + $this->assertEmpty($aResult, 'Expected result to be empty array when input is null.'); + } + + //--- ExecuteCleanup tests --- + + public function testExecuteCleanup_DeleteOneObjPerClassWithoutLimit() + { + $this->GivenDFRTreeInDB(<<ExecuteCleanup($aClasses); + $aExpected = [ + ['DFRToUpdate', 1, 0 ], + ['DFRToRemoveLeaf', 0, 1 ], + ['DFRRemovedCollateral', 0, 1 ], + ['DFRRemovedCollateralCascade', 0, 1 ], + ]; + $this->AssertSummaryEquals($aExpected, $aRes); + } + + public function testExecuteCleanup_DeleteManyObjPerClassWithoutLimit() + { + $this->GivenDFRTreeInDB(<<ExecuteCleanup($aClasses); + $aExpected = [ + ['DFRToUpdate', 3, 0 ], + ['DFRToRemoveLeaf', 0, 3 ], + ['DFRRemovedCollateral', 0, 3 ], + ['DFRRemovedCollateralCascade', 0, 3 ], + ]; + $this->AssertSummaryEquals($aExpected, $aRes); + } + + public function testGetCleanupSummary_DeleteManyObjPerClassWithoutLimit() + { + $this->GivenDFRTreeInDB(<<GetCleanupSummary($aClasses); + $aExpected = [ + ['DFRToUpdate', 3, 0 ], + ['DFRToRemoveLeaf', 0, 3 ], + ['DFRRemovedCollateral', 0, 3 ], + ['DFRRemovedCollateralCascade', 0, 3 ], + ]; + $this->AssertSummaryEquals($aExpected, $aRes); + } + + public function testExecuteCleanup_ManualDeleteShouldFail() + { + $this->GivenDFRTreeInDB(<<expectException(DataFeatureRemovalException::class); + $this->expectExceptionMessage('Deletion Plan cannot be executed due to issues'); + $oService = new DataCleanupService(); + $oService->ExecuteCleanup($aClasses); + } + + public function testGetCleanupSummary_ManualDeleteShouldFail() + { + $this->GivenDFRTreeInDB(<<GetCleanupSummary($aClasses); + $aExpected = [ + ['DFRManual', 0, 0, 3 ], + ['DFRToRemoveLeaf', 0, 2], + ]; + $this->AssertSummaryEquals($aExpected, $aRes); + } + + private function AssertSummaryEquals(array $expected, $actual, $sMessage = '') + { + $aExpected = []; + foreach ($expected as $line) { + $sClass = $line[0]; + $iUpdate = $line[1]; + $iDelete = $line[2]; + $iIssue = $line[3] ?? 0; + $iTotalUpdate = $line[4] ?? $iUpdate; + $iTotalDelete = $line[5] ?? $iDelete; + + $oCleanupSummaryEntity = new DataCleanupSummaryEntity($sClass); + $oCleanupSummaryEntity->iUpdateCount = $iUpdate; + $oCleanupSummaryEntity->iDeleteCount = $iDelete; + $oCleanupSummaryEntity->iIssueCount = $iIssue; + $oCleanupSummaryEntity->iTotalUpdateCount = $iTotalUpdate; + $oCleanupSummaryEntity->iTotalDeleteCount = $iTotalDelete; + + $aExpected[$sClass] = $oCleanupSummaryEntity; + } + $this->assertEquals($aExpected, $actual, $sMessage); + } + + public static function ExecuteCleanup_StopInProcessKeepDatabaseOk(): array + { + return [ + 'Stop after 1' => [ + 1, + [ + ['DFRToUpdate', 1, 0], + ], + ], + 'Stop after 2' => [ + 2, + [ + ['DFRToUpdate', 1, 0], + ['DFRRemovedCollateralCascade', 0, 1], + ], + ], + 'Stop after 3' => [ + 3, + [ + ['DFRToUpdate', 1, 0], + ['DFRRemovedCollateralCascade', 0, 1], + ['DFRRemovedCollateral', 0, 1], + ], + ], + 'Stop after 4' => [ + 4, + [ + ['DFRToUpdate', 1, 0], + ['DFRRemovedCollateralCascade', 0, 1], + ['DFRRemovedCollateral', 0, 1], + ['DFRToRemoveLeaf', 0, 1], + ], + ], + 'Stop after 5' => [ + 5, + [ + ['DFRToUpdate', 2, 0], + ['DFRRemovedCollateralCascade', 0, 1], + ['DFRRemovedCollateral', 0, 1], + ['DFRToRemoveLeaf', 0, 1], + ], + ], + ]; + } + + /** + * @dataProvider ExecuteCleanup_StopInProcessKeepDatabaseOk + */ + public function testExecuteCleanup_StopInProcessKeepDatabaseOk(int $iExecutionCount, array $aExpected): void + { + $this->GivenDFRTreeInDB(<<GivenExecutionLimits($iExecutionCount); + $this->SetNonPublicProperty($oDeletionPlaService, 'oExecutionLimits', $this->oExecutionLimits); + $aRes = $oDeletionPlaService->ExecuteCleanup($aClasses); + $this->AssertSummaryEquals($aExpected, $aRes); + } + + private function GivenDFRTreeInDB(string $sTree) + { + $aTree = explode("\n", $sTree); + foreach ($aTree as $sLine) { + if (trim($sLine) === "") { + continue; + } + $this->GivenDFRTreeLineInDB($sLine); + } + } + + private array $aIdByObjectName = []; + private function GivenDFRTreeLineInDB(string $sLine) + { + [$sLeft, $sRight] = explode('<-', $sLine); + $sLeft = trim($sLeft); + + $iLeftId = $this->aIdByObjectName[$sLeft] ?? 0; + if ($iLeftId === 0) { + [$sChildClass, ] = explode('_', $sLeft, 2); + $iLeftId = $this->GivenObjectInDB($sChildClass, ['name' => $sLeft]); + $this->aIdByObjectName[$sLeft] = $iLeftId; + } + + $sRight = trim($sRight); + [$sChildClass, ] = explode('_', $sRight, 2); + $iRightId = $this->GivenObjectInDB($sChildClass, ['name' => $sRight, 'extkey_id' => $iLeftId]); + $this->aIdByObjectName[$sRight] = $iRightId; + } + + private function GivenExecutionLimits(int $iStopAfterCallNumberReached): void + { + $matcher = $this->any(); + + $this->oExecutionLimits = $this->createMock(ExecutionLimits::class); + $this->oExecutionLimits->expects($matcher) + ->method('ShouldStopExecution')->willReturnCallback(function () use ($matcher, $iStopAfterCallNumberReached) { + $invocationCount = $matcher->getInvocationCount(); + + return ($invocationCount >= $iStopAfterCallNumberReached); + }); + } +} diff --git a/tests/php-unit-tests/unitary-tests/datamodels/2.x/combodo-data-feature-removal/data_cleanup_delta.xml b/tests/php-unit-tests/unitary-tests/datamodels/2.x/combodo-data-feature-removal/data_cleanup_delta.xml new file mode 100644 index 0000000000..a338e1fbc5 --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/datamodels/2.x/combodo-data-feature-removal/data_cleanup_delta.xml @@ -0,0 +1,346 @@ + + + + + + bizmodel,searchable + true + dfrtoremove + + + + + + + + + + name + + true + + + all + + + + + + + + + + +
    + + + 10 + + +
    +
    + cmdbAbstractObject +
    + + + bizmodel,searchable + false + dfrtoupdate + + + + + + + + + + name + + true + + + all + + + extkey_id + + + true + DFRToRemove + DEL_AUTO + all + + + + + + + + + + +
    + + + 10 + + + 20 + + +
    +
    + cmdbAbstractObject +
    + + + bizmodel,searchable + false + dfrremovedcollateral + + + + + + + + + + name + + true + + + all + + + extkey_id + + + false + DFRToRemove + DEL_AUTO + all + + + + + + + + + + +
    + + + 10 + + + 20 + + +
    +
    + cmdbAbstractObject +
    + + + bizmodel,searchable + false + dfrtoremoveleaf + + + + + + + + + + desc + + true + + + all + + + + + + + + + + +
    + + + 10 + + + 20 + + +
    +
    + DFRToRemove +
    + + + bizmodel,searchable + false + dfrremovedcollateralcascade + + + + + + + + + + name + + true + + + all + + + extkey_id + + + false + DFRRemovedCollateral + DEL_AUTO + all + + + + + + + + + + +
    + + + 10 + + + 20 + + +
    +
    + cmdbAbstractObject +
    + + + bizmodel,searchable + false + dfrmanual + + + + + + + + + + name + + true + + + all + + + extkey_id + + + false + DFRToRemove + DEL_MANUAL + all + + + + + + + + + + +
    + + + 10 + + + 20 + + +
    +
    + cmdbAbstractObject +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    diff --git a/tests/php-unit-tests/unitary-tests/datamodels/2.x/combodo-data-feature-removal/simulate-audit-from-setup.php b/tests/php-unit-tests/unitary-tests/datamodels/2.x/combodo-data-feature-removal/simulate-audit-from-setup.php new file mode 100644 index 0000000000..34d0c7e181 --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/datamodels/2.x/combodo-data-feature-removal/simulate-audit-from-setup.php @@ -0,0 +1,89 @@ + "combodo-data-feature-removal", + "exec_page" => "index.php", + 'exec_env' => 'production', +]; + +new ContextTag(ContextTag::TAG_SETUP); +$sToken = SetupUtils::CreateSetupToken(); + +function GetLastestInstallFile(): ?string +{ + $aFiles = glob(APPROOT.'/log/install-*.xml'); + rsort($aFiles); + $iLatestCtime = 0; + $sLastFilePath = null; + foreach ($aFiles as $sFilePath) { + if (is_file($sFilePath)) { + $iCurrentCtime = filemtime($sFilePath); + if ($iCurrentCtime > $iLatestCtime) { + $iLatestCtime = $iCurrentCtime; + $sLastFilePath = $sFilePath; + } + } + } + + return $sLastFilePath; +} + +$aRemovedExtensions = ['itop-container-mgmt' => 'Containerization']; + +$sPath = GetLastestInstallFile(); +if (is_null($sPath)) { + throw new Exception("$sPath no installation XM. Launch a setup...."); +} +$aParams = new XMLParameters($sPath); +$aSelectedModules = array_filter($aParams->Get('selected_modules', []), static function ($element) { + global $aRemovedExtensions; + return ! array_key_exists($element, $aRemovedExtensions); +}); + +$aSelectedExtensions = array_filter($aParams->Get('selected_extensions', []), static function ($element) { + global $aRemovedExtensions; + return ! array_key_exists($element, $aRemovedExtensions); +}); + +$aPostParams = [ + "auth_user" => 'admin', + "auth_pwd" => 'admin', + 'login_mode' => 'form', + 'operation' => 'AnalysisResult', + 'setup_token' => $sToken, + 'selected_modules' => utils::HtmlEntities(json_encode($aSelectedModules)), + 'selected_extensions' => utils::HtmlEntities(json_encode($aSelectedExtensions)), + 'removed_extensions' => utils::HtmlEntities(json_encode($aRemovedExtensions)), +]; + +$sHiddenPostedInput = ""; +foreach ($aPostParams as $sKey => $sVal) { + $sHiddenPostedInput .= << +INPUT; +} + +$sRedirectURL = utils::GetAbsoluteUrlModulePage('combodo-data-feature-removal', 'index.php'); + +$sDiv = << +DIV; + +$sReadyJs = <<add($sDiv); +$oP->add_ready_script($sReadyJs); +$oP->output(); diff --git a/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-config/ConfigTest/config-itop-joker.php b/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-config/ConfigTest/config-itop-joker.php index 7c4a359c28..cbce0bb87d 100644 --- a/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-config/ConfigTest/config-itop-joker.php +++ b/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-config/ConfigTest/config-itop-joker.php @@ -7,30 +7,26 @@ * * */ -$MySettings = array( - - +$MySettings = [ // app_root_url: Root URL used for navigating within the application, or from an email to the application (you can put $SERVER_NAME$ as a placeholder for the server's name) // default: '' 'app_root_url' => 'http://%server(SERVER_NAME)?:localhost%/itop/iTop/', - -); +]; /** * * Modules specific settings * */ -$MyModuleSettings = array( -); +$MyModuleSettings = [ +]; /** * * Data model modules to be loaded. Names are specified as relative paths * */ -$MyModules = array( -); -?> \ No newline at end of file +$MyModules = [ +]; diff --git a/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-config/ConfigTest/config-itop-var.php b/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-config/ConfigTest/config-itop-var.php index a9e41ee35f..3dc1986cd1 100644 --- a/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-config/ConfigTest/config-itop-var.php +++ b/tests/php-unit-tests/unitary-tests/datamodels/2.x/itop-config/ConfigTest/config-itop-var.php @@ -7,30 +7,26 @@ * * */ -$MySettings = array( - - +$MySettings = [ // app_root_url: Root URL used for navigating within the application, or from an email to the application (you can put $SERVER_NAME$ as a placeholder for the server's name) // default: '' - 'app_root_url' => 'http://' . (isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'localhost') . '/itop/iTop/', + 'app_root_url' => 'http://'.(isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'localhost').'/itop/iTop/', - -); +]; /** * * Modules specific settings * */ -$MyModuleSettings = array( -); +$MyModuleSettings = [ +]; /** * * Data model modules to be loaded. Names are specified as relative paths * */ -$MyModules = array( -); -?> \ No newline at end of file +$MyModules = [ +]; diff --git a/tests/php-unit-tests/unitary-tests/modulediscovery/ModuleDiscoveryTest.php b/tests/php-unit-tests/unitary-tests/modulediscovery/ModuleDiscoveryTest.php deleted file mode 100644 index d863c6d64f..0000000000 --- a/tests/php-unit-tests/unitary-tests/modulediscovery/ModuleDiscoveryTest.php +++ /dev/null @@ -1,50 +0,0 @@ - [ - 'sModuleId' => 'a/1.2.3', - 'name' => 'a', - 'version' => '1.2.3', - ], - 'develop' => [ - 'sModuleId' => 'a/1.2.3-dev', - 'name' => 'a', - 'version' => '1.2.3-dev', - ], - 'missing version => 1.0.0' => [ - 'sModuleId' => 'a/', - 'name' => 'a', - 'version' => '1.0.0', - ], - 'missing everything except name' => [ - 'sModuleId' => 'a', - 'name' => 'a', - 'version' => '1.0.0', - ], - ]; - } - - protected function setUp(): void - { - parent::setUp(); - - $this->RequireOnceItopFile('setup/modulediscovery.class.inc.php'); - } - - /** - * @dataProvider GetModuleNameProvider - */ - public function testGetModuleName($sModuleId, $expectedName, $expectedVersion) - { - $this->assertEquals([$expectedName, $expectedVersion], \ModuleDiscovery::GetModuleName($sModuleId)); - } - -} diff --git a/tests/php-unit-tests/unitary-tests/setup/ExtensionsMapTest.php b/tests/php-unit-tests/unitary-tests/setup/ExtensionsMapTest.php index df63c2ebe2..0dec4dc9d5 100644 --- a/tests/php-unit-tests/unitary-tests/setup/ExtensionsMapTest.php +++ b/tests/php-unit-tests/unitary-tests/setup/ExtensionsMapTest.php @@ -3,6 +3,7 @@ namespace Combodo\iTop\Test\UnitTest\Integration; use Combodo\iTop\Test\UnitTest\ItopTestCase; +use iTopExtension; use ItopExtensionsMap; use ModuleDiscovery; @@ -23,4 +24,162 @@ class ExtensionsMapTest extends ItopTestCase $this->assertGreaterThan(0, count($aExtensions)); } + public function testGetAllExtensionsToDisplayInSetup() + { + $oExtensionsMap = $this->GiveExtensionMapWithAllTypeOfExtensions(); + + $aExtensions = $oExtensionsMap->GetAllExtensionsToDisplayInSetup(); + $expected = [ + 'installed_ext1', + 'ext1', + ]; + $this->assertEquals($expected, array_keys($aExtensions)); + } + + public function testGetAllExtensionsToDisplayInSetup_WithExtensionsHavingDependencyIssues() + { + $oExtensionsMap = $this->GiveExtensionMapWithAllTypeOfExtensions(); + + $aExtensions = $oExtensionsMap->GetAllExtensionsToDisplayInSetup(true); + $expected = [ + 'installed_ext1', + 'installed_ext_with_deps_issues', + 'ext1', + 'ext_with_deps_issues', + ]; + $this->assertEquals($expected, array_keys($aExtensions)); + } + + public function testGetAllExtensionsToDisplayInSetup_LegacyPackage() + { + $oExtensionsMap = $this->GiveExtensionMapWithAllTypeOfExtensions(); + + $this->SetNonPublicProperty($oExtensionsMap, 'bHasXmlInstallationFile', false); + $aExtensions = $oExtensionsMap->GetAllExtensionsToDisplayInSetup(); + $expected = [ + 'installed_ext1', + 'installed_ext_in_package', + 'ext1', + 'ext_in_package', + ]; + $this->assertEquals($expected, array_keys($aExtensions)); + } + + public function testGetAllExtensionsToDisplayInSetup_LegacyPackage_WithExtensionsHavingDependencyIssues() + { + $oExtensionsMap = $this->GiveExtensionMapWithAllTypeOfExtensions(); + + $this->SetNonPublicProperty($oExtensionsMap, 'bHasXmlInstallationFile', false); + $aExtensions = $oExtensionsMap->GetAllExtensionsToDisplayInSetup(true); + $expected = [ + 'installed_ext1', + 'installed_ext_in_package', + 'installed_ext_with_deps_issues', + 'ext1', + 'ext_in_package', + 'ext_with_deps_issues', + ]; + $this->assertEquals($expected, array_keys($aExtensions)); + } + + private function GiveExtensionMapWithAllTypeOfExtensions(): iTopExtensionsMap + { + $oExtensionsMap = new iTopExtensionsMap(); + $this->SetNonPublicProperty($oExtensionsMap, 'aInstalledExtensions', []); + $this->SetNonPublicProperty($oExtensionsMap, 'aExtensions', []); + + $this->AddExtension( + $oExtensionsMap, + $this->GivenExtension("installed_ext1", "123", true, iTopExtension::SOURCE_REMOTE, true, []), + 'aInstalledExtensions' + ); + $this->AddExtension( + $oExtensionsMap, + $this->GivenExtension("installed_notvisible", "123", false, iTopExtension::SOURCE_REMOTE, true, []), + 'aInstalledExtensions' + ); + $this->AddExtension( + $oExtensionsMap, + $this->GivenExtension("installed_ext_in_package", "123", true, iTopExtension::SOURCE_WIZARD, true, []), + 'aInstalledExtensions' + ); + $this->AddExtension( + $oExtensionsMap, + $this->GivenExtension("installed_ext_with_deps_issues", "123", true, iTopExtension::SOURCE_REMOTE, true, ["aa"]), + 'aInstalledExtensions' + ); + $this->AddExtension( + $oExtensionsMap, + $this->GivenExtension("ext1", "123", true, iTopExtension::SOURCE_REMOTE, true, []), + 'aExtensions' + ); + $this->AddExtension( + $oExtensionsMap, + $this->GivenExtension("notvisible", "123", false, iTopExtension::SOURCE_REMOTE, true, []), + 'aExtensions' + ); + $this->AddExtension( + $oExtensionsMap, + $this->GivenExtension("ext_in_package", "123", true, iTopExtension::SOURCE_WIZARD, true, []), + 'aExtensions' + ); + $this->AddExtension( + $oExtensionsMap, + $this->GivenExtension("ext_with_deps_issues", "123", true, iTopExtension::SOURCE_REMOTE, true, ["aa"]), + 'aExtensions' + ); + + return $oExtensionsMap; + } + + private function GivenExtension(string $sCode, string $sVersion, bool $bVisible, string $sSource, bool $bMandatory, array $aMissingDependencies = []): iTopExtension + { + $oExt = new iTopExtension(); + $oExt->sCode = $sCode; + $oExt->sVersion = $sVersion; + $oExt->bVisible = $bVisible; + $oExt->sSource = $sSource; + $oExt->aMissingDependencies = $aMissingDependencies; + $oExt->bMandatory = $bMandatory; + return $oExt; + } + + private function AddExtension(iTopExtensionsMap $oExtensionsMap, iTopExtension $oExt, string $mapKeyInItopExtensionMap) + { + $aMap = $this->GetNonPublicProperty($oExtensionsMap, $mapKeyInItopExtensionMap); + $aMap[$oExt->sCode.'/'.$oExt->sVersion] = $oExt; + $this->SetNonPublicProperty($oExtensionsMap, $mapKeyInItopExtensionMap, $aMap); + } + + public function testiTopExtensionsMapInit() + { + $oiTopExtensionsMap = new iTopExtensionsMap(sAppRootForTests:__DIR__."/ressources"); + + //file_put_contents(__DIR__.'/ressources/all_extensions_from_datamodels.json', json_encode($this->SerializeExtensionMap($oiTopExtensionsMap), JSON_PRETTY_PRINT)); + + $sExpected = file_get_contents(__DIR__.'/ressources/all_extensions_from_datamodels.json'); + $sExpected = str_replace('"sVersion": "ITOP_VERSION"', '"sVersion": "'.ITOP_VERSION.'"', $sExpected); + $sExpected = preg_replace('/"module_file_path": .*/', '"module_file_path": ANYPATH', $sExpected); + + $actual = json_encode($this->SerializeExtensionMap($oiTopExtensionsMap), JSON_PRETTY_PRINT); + $actual = preg_replace('/"module_file_path": .*/', '"module_file_path": ANYPATH', $actual); + $this->assertEquals($sExpected, $actual); + } + + public function SerializeExtensionMap(iTopExtensionsMap $oiTopExtensionsMap): array + { + $aRes = []; + foreach ($oiTopExtensionsMap->GetAllExtensions() as $oExtension) { + $aRes[] = [ + 'sCode' => $oExtension->sCode, + 'sSource' => $oExtension->sSource, + 'sVersion' => $oExtension->sVersion, + 'aModules' => $oExtension->aModules, + 'aModuleVersion' => $oExtension->aModuleVersion, + 'aModuleInfo' => $oExtension->aModuleInfo, + ]; + } + + return $aRes; + } } diff --git a/tests/php-unit-tests/unitary-tests/setup/ModuleDiscoveryTest.php b/tests/php-unit-tests/unitary-tests/setup/ModuleDiscoveryTest.php index 4e31921c9e..a3b223f29d 100644 --- a/tests/php-unit-tests/unitary-tests/setup/ModuleDiscoveryTest.php +++ b/tests/php-unit-tests/unitary-tests/setup/ModuleDiscoveryTest.php @@ -2,7 +2,9 @@ namespace Combodo\iTop\Test\UnitTest\Setup; +use Combodo\iTop\Setup\ModuleDiscovery\ModuleFileReader; use Combodo\iTop\Test\UnitTest\ItopTestCase; +use iTopExtension; use MissingDependencyException; use ModuleDiscovery; @@ -15,6 +17,12 @@ class ModuleDiscoveryTest extends ItopTestCase $this->RequireOnceItopFile('setup/modulediscovery.class.inc.php'); } + protected function tearDown(): void + { + parent::tearDown(); + ModuleDiscovery::DeclareRemovedExtensions([]); + } + public function testOrderModulesByDependencies_RealExample() { $aModules = json_decode(file_get_contents(__DIR__.'/ressources/reallife_discovered_modules.json'), true); @@ -77,4 +85,126 @@ TXT; ModuleDiscovery::OrderModulesByDependencies($aModules, true, $aChoices); } + + public function testOrderModulesByDependencies_FailWhenChoosenModuleDependsOnRemovedExtensionModule() + { + $aChoices = ['id1', 'id2']; + + $sModuleFilePath = $this->GetTemporaryFilePath(); + $sModuleFilePath2 = $this->GetTemporaryFilePath(); + + $aModules = [ + "id1/1" => [ + 'dependencies' => [ 'id2/2'], + 'label' => 'label1', + ModuleFileReader::MODULE_FILE_PATH => $sModuleFilePath, + ], + "id2/2" => [ + 'dependencies' => [], + 'label' => 'label2', + ModuleFileReader::MODULE_FILE_PATH => $sModuleFilePath2, + ], + ]; + + $oExtension = $this->GivenExtensionWithModule('id2', '2', $sModuleFilePath2); + ModuleDiscovery::DeclareRemovedExtensions([$oExtension]); + + $sExpectedMessage = <<expectException(MissingDependencyException::class); + $this->expectExceptionMessage($sExpectedMessage); + + ModuleDiscovery::OrderModulesByDependencies($aModules, true, $aChoices); + } + + public function GetModuleNameProvider() + { + return [ + 'nominal' => [ + 'sModuleId' => 'a/1.2.3', + 'name' => 'a', + 'version' => '1.2.3', + ], + 'develop' => [ + 'sModuleId' => 'a/1.2.3-dev', + 'name' => 'a', + 'version' => '1.2.3-dev', + ], + 'missing version => 1.0.0' => [ + 'sModuleId' => 'a/', + 'name' => 'a', + 'version' => '1.0.0', + ], + 'missing everything except name' => [ + 'sModuleId' => 'a', + 'name' => 'a', + 'version' => '1.0.0', + ], + ]; + } + + /** + * @dataProvider GetModuleNameProvider + */ + public function testGetModuleName($sModuleId, $expectedName, $expectedVersion) + { + $this->assertEquals([$expectedName, $expectedVersion], ModuleDiscovery::GetModuleName($sModuleId)); + } + + public function testIsModuleInExtensionList_NoRemovedExtension() + { + $this->assertFalse($this->InvokeNonPublicStaticMethod(ModuleDiscovery::class, "IsModuleInExtensionList", [[], 'module_name', '123', []])); + } + + public function testIsModuleInExtensionList_ModuleWithAnotherVersionIncludedInRemoveExtension() + { + $sModuleFilePath = $this->GetTemporaryFilePath(); + $aExtensionList = [$this->GivenExtensionWithModule('module_name', '456', $sModuleFilePath)]; + $this->AssertModuleIsPartOfRemovedExtension($aExtensionList, 'module_name', '123', $sModuleFilePath, false); + } + + public function testIsModuleInExtensionList_AnotherModuleWithSameVersionIncludedInRemoveExtension() + { + $sModuleFilePath = $this->GetTemporaryFilePath(); + $aExtensionList = [$this->GivenExtensionWithModule('module_name', '456', $sModuleFilePath)]; + $this->AssertModuleIsPartOfRemovedExtension($aExtensionList, 'another_module_name', '456', $sModuleFilePath, false); + } + + public function testIsModuleInExtensionList_SameExtensionComingFromAnotherLocation() + { + $sModuleFilePath = $this->GetTemporaryFilePath(); + $sModuleFilePath2 = $this->GetTemporaryFilePath(); + $aExtensionList = [$this->GivenExtensionWithModule('module_name', '456', $sModuleFilePath2)]; + $this->AssertModuleIsPartOfRemovedExtension($aExtensionList, 'module_name', '456', $sModuleFilePath, false); + } + + public function testIsModuleInExtensionList_ModuleShouldBeExcluded() + { + $sModuleFilePath = $this->GetTemporaryFilePath(); + $aExtensionList = [$this->GivenExtensionWithModule('module_name', '456', $sModuleFilePath)]; + $this->AssertModuleIsPartOfRemovedExtension($aExtensionList, 'module_name', '456', $sModuleFilePath, true); + } + + public function AssertModuleIsPartOfRemovedExtension($aExtensionList, $sModuleName, $sModuleVersion, $sModuleFilePath, $bExpected) + { + $aCurrentModuleInfo = [ + ModuleFileReader::MODULE_FILE_PATH => $sModuleFilePath, + ]; + $this->assertEquals( + $bExpected, + $this->InvokeNonPublicStaticMethod(ModuleDiscovery::class, "IsModuleInExtensionList", [$aExtensionList, $sModuleName, $sModuleVersion, $aCurrentModuleInfo]) + ); + } + + private function GivenExtensionWithModule(string $sModuleName, string $sVersion, bool|string $sModuleFilePath): iTopExtension + { + $oExt = new iTopExtension(); + $oExt->aModuleVersion[$sModuleName] = $sVersion; + $oExt->aModuleInfo[$sModuleName] = [ + ModuleFileReader::MODULE_FILE_PATH => $sModuleFilePath, + ]; + return $oExt; + } } diff --git a/tests/php-unit-tests/unitary-tests/setup/ModuleInstallerAPITest.php b/tests/php-unit-tests/unitary-tests/setup/ModuleInstallerAPITest.php index a201d0e085..da4a9d2239 100644 --- a/tests/php-unit-tests/unitary-tests/setup/ModuleInstallerAPITest.php +++ b/tests/php-unit-tests/unitary-tests/setup/ModuleInstallerAPITest.php @@ -354,21 +354,6 @@ SQL ]; } - /** - * @covers \ModuleInstallerAPI::LoadLocalizedData - * @dataProvider LoadLocalizedData_InvalidParametersProvider - */ - public function testLoadLocalizedData_ThrowsOnInvalidParameters(string $sPreviousVersion, string $sCurrentVersion, string $sFirstLoadingVersion, string $sPattern, string $sExpectedMessage): void - { - $oConfig = MetaModel::GetConfig(); - $this->assertNotNull($oConfig); - - $this->expectException(\CoreUnexpectedValue::class); - $this->expectExceptionMessage($sExpectedMessage); - - ModuleInstallerAPI::LoadLocalizedData($oConfig, $sPreviousVersion, $sCurrentVersion, $sFirstLoadingVersion, $sPattern); - } - public function LoadLocalizedData_InvalidParametersProvider(): array { $sTmpDir = static::CreateTmpdir(); diff --git a/tests/php-unit-tests/unitary-tests/setup/RunTimeEnvironmentTest.php b/tests/php-unit-tests/unitary-tests/setup/RunTimeEnvironmentTest.php new file mode 100644 index 0000000000..b753907c51 --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/RunTimeEnvironmentTest.php @@ -0,0 +1,98 @@ +RequireOnceItopFile('/setup/runtimeenv.class.inc.php'); + } + + protected function tearDown(): void + { + if (($this->sFixtureRootDir !== null) && is_dir($this->sFixtureRootDir)) { + self::RecurseRmdir($this->sFixtureRootDir); + } + if (($this->sBuildDirToCleanup !== null) && is_dir($this->sBuildDirToCleanup)) { + self::RecurseRmdir($this->sBuildDirToCleanup); + } + + parent::tearDown(); + } + + public function testDoCompileThrowsWhenExtensionCodeIsMissing(): void + { + [$sToken, $sSourceDirRelative, $sExtensionsDirRelative] = $this->CreateFixtureContext('runtimeenv-missing-code-'); + + $sInvalidExtensionXml = << + + + Test extension without code + 1.0.0 + false + + +XML; + file_put_contents(APPROOT.$sExtensionsDirRelative.'/extension.xml', $sInvalidExtensionXml); + $oRunTimeEnvironment = $this->CreateRunTimeEnvironment($sToken); + + $this->expectException(Exception::class); + $this->expectExceptionMessage('Extension "Broken extension" cannot be installed: Missing extension code'); + + $oRunTimeEnvironment->DoCompile([], [], $sSourceDirRelative, $sExtensionsDirRelative, false); + } + + public function testDoCompileThrowsWhenExtensionCodeAndLabelAreMissing(): void + { + [$sToken, $sSourceDirRelative, $sExtensionsDirRelative] = $this->CreateFixtureContext('runtimeenv-missing-label-'); + + $sInvalidExtensionXml = << + + Test extension without code and label + 1.0.0 + false + + +XML; + $sExtensionsDirAbsolute = APPROOT.$sExtensionsDirRelative; + file_put_contents($sExtensionsDirAbsolute.'/extension.xml', $sInvalidExtensionXml); + $oRunTimeEnvironment = $this->CreateRunTimeEnvironment($sToken); + + $this->expectException(Exception::class); + $this->expectExceptionMessage(sprintf('Extension "%s" cannot be installed: Missing extension code', $sExtensionsDirAbsolute)); + + $oRunTimeEnvironment->DoCompile([], [], $sSourceDirRelative, $sExtensionsDirRelative, false); + } + + private function CreateFixtureContext(string $sTokenPrefix): array + { + $sToken = str_replace('.', '-', uniqid($sTokenPrefix, true)); + $this->sFixtureRootDir = APPROOT.'data/'.$sToken; + $sSourceDirRelative = 'data/'.$sToken.'/source'; + $sExtensionsDirRelative = 'data/'.$sToken.'/extensions'; + + mkdir(APPROOT.$sSourceDirRelative, 0777, true); + mkdir(APPROOT.$sExtensionsDirRelative, 0777, true); + + return [$sToken, $sSourceDirRelative, $sExtensionsDirRelative]; + } + + private function CreateRunTimeEnvironment(string $sToken): RunTimeEnvironment + { + $oRunTimeEnvironment = new RunTimeEnvironment('test-'.$sToken, false); + $this->sBuildDirToCleanup = $oRunTimeEnvironment->GetBuildDir(); + + return $oRunTimeEnvironment; + } +} diff --git a/tests/php-unit-tests/unitary-tests/setup/WebPageFake.php b/tests/php-unit-tests/unitary-tests/setup/WebPageFake.php new file mode 100644 index 0000000000..e157eaa190 --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/WebPageFake.php @@ -0,0 +1,16 @@ +sContent .= $sContent; + } +} diff --git a/tests/php-unit-tests/unitary-tests/setup/WizStepModulesChoiceFake.php b/tests/php-unit-tests/unitary-tests/setup/WizStepModulesChoiceFake.php new file mode 100644 index 0000000000..6b2ed3caf8 --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/WizStepModulesChoiceFake.php @@ -0,0 +1,15 @@ +oWizard = $oWizard; + $this->sCurrentState = $sCurrentState; + } + + public function setExtensionMap(iTopExtensionsMap $oMap) + { + $this->oExtensionsMap = $oMap; + } +} diff --git a/tests/php-unit-tests/unitary-tests/setup/WizStepModulesChoiceTest.php b/tests/php-unit-tests/unitary-tests/setup/WizStepModulesChoiceTest.php new file mode 100644 index 0000000000..45ef05f7a6 --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/WizStepModulesChoiceTest.php @@ -0,0 +1,1454 @@ +RequireOnceItopFile('/setup/unattended-install/InstallationFileService.php'); + require_once __DIR__.'/WebPageFake.php'; + require_once __DIR__.'/iTopExtensionsMapFake.php'; + require_once __DIR__.'/WizStepModulesChoiceFake.php'; + + $this->oWizard = new WizardController('', ''); + $this->oWizStepModulesChoiceFake = new WizStepModulesChoiceFake($this->oWizard, ''); + ModuleDiscovery::ResetCache(); + } + + public function ProviderComputeChoiceFlags() + { + return [ + 'A not selected, not installed extension should not be checked and be enabled' => [ + 'aExtensionsOnDiskOrDb' => [ + 'itop-ext1' => [ + 'installed' => false, + ], + ], + 'aWizardStepDefinition' => [ + 'extension_code' => 'itop-ext1', + 'mandatory' => false, + 'uninstallable' => true, + ], + 'bCurrentSelected' => false, + 'bDisableUninstallChecks' => false, + 'aExpectedFlags' => [ + 'uninstallable' => true, + 'missing' => false, + 'installed' => false, + 'disabled' => false, + 'checked' => false, + ], + ], + 'A selected but not installed extension should be checked and enabled' => [ + 'aExtensionsOnDiskOrDb' => [ + 'itop-ext1' => [ + 'installed' => false, + ], + ], + 'aWizardStepDefinition' => [ + 'extension_code' => 'itop-ext1', + 'mandatory' => false, + 'uninstallable' => true, + ], + 'bCurrentSelected' => true, + 'bDisableUninstallChecks' => false, + 'aExpectedFlags' => [ + 'uninstallable' => true, + 'missing' => false, + 'installed' => false, + 'disabled' => false, + 'checked' => true, + ], + ], + 'A missing extension should be disabled and unchecked' => [ + 'aExtensionsOnDiskOrDb' => [ + ], + 'aWizardStepDefinition' => [ + 'extension_code' => 'itop-ext1', + 'mandatory' => false, + 'missing' => true, + 'uninstallable' => true, + ], + 'bCurrentSelected' => false, + 'bDisableUninstallChecks' => false, + 'aExpectedFlags' => [ + 'uninstallable' => true, + 'missing' => true, + 'installed' => true, + 'disabled' => true, + 'checked' => false, + ], + ], + 'A missing extension should always be disabled and unchecked, even when mandatory' => [ + 'aExtensionsOnDiskOrDb' => [ + ], + 'aWizardStepDefinition' => [ + 'extension_code' => 'itop-ext1', + 'mandatory' => true, + 'missing' => true, + 'uninstallable' => true, + ], + 'bCurrentSelected' => false, + 'bDisableUninstallChecks' => false, + 'aExpectedFlags' => [ + 'uninstallable' => true, + 'missing' => true, + 'installed' => true, + 'disabled' => true, + 'checked' => false, + ], + ], + 'A missing extension should always be disabled and unchecked, even when non-uninstallable' => [ + 'aExtensionsOnDiskOrDb' => [ + ], + 'aWizardStepDefinition' => [ + 'extension_code' => 'itop-ext1', + 'mandatory' => true, + 'missing' => true, + 'uninstallable' => false, + ], + 'bCurrentSelected' => false, + 'bDisableUninstallChecks' => false, + 'aExpectedFlags' => [ + 'uninstallable' => false, + 'missing' => true, + 'installed' => true, + 'disabled' => true, + 'checked' => false, + ], + ], + 'An installed but not selected extension should not be checked and be enabled' => [ + 'aExtensionsOnDiskOrDb' => [ + 'itop-ext1' => [ + 'installed' => true, + ], + ], + 'aWizardStepDefinition' => [ + 'extension_code' => 'itop-ext1', + 'mandatory' => false, + 'uninstallable' => true, + ], + 'bCurrentSelected' => false, + 'bDisableUninstallChecks' => false, + 'aExpectedFlags' => [ + 'uninstallable' => true, + 'missing' => false, + 'installed' => true, + 'disabled' => false, + 'checked' => false, + ], + ], + 'An installed non uninstallable extension should be checked and disabled' => [ + 'aExtensionsOnDiskOrDb' => [ + 'itop-ext1' => [ + 'installed' => true, + ], + ], + 'aWizardStepDefinition' => [ + 'extension_code' => 'itop-ext1', + 'mandatory' => false, + 'uninstallable' => false, + ], + 'bCurrentSelected' => false, + 'bDisableUninstallChecks' => false, + 'aExpectedFlags' => [ + 'uninstallable' => false, + 'missing' => false, + 'installed' => true, + 'disabled' => true, + 'checked' => true, + ], + ], + 'An installed non uninstallable extension should be enabled if the "disable uninstallation check" flag is set' => [ + 'aExtensionsOnDiskOrDb' => [ + 'itop-ext1' => [ + 'installed' => true, + ], + ], + 'aWizardStepDefinition' => [ + 'extension_code' => 'itop-ext1', + 'mandatory' => false, + 'uninstallable' => false, + ], + 'bCurrentSelected' => true, + 'bDisableUninstallChecks' => true, + 'aExpectedFlags' => [ + 'uninstallable' => false, + 'missing' => false, + 'installed' => true, + 'disabled' => false, + 'checked' => true, + ], + ], + 'A mandatory extension should be checked and disabled' => [ + 'aExtensionsOnDiskOrDb' => [ + 'itop-ext1' => [ + 'installed' => false, + ], + ], + 'aWizardStepDefinition' => [ + 'extension_code' => 'itop-ext1', + 'mandatory' => true, + 'uninstallable' => true, + ], + 'bCurrentSelected' => false, + 'bDisableUninstallChecks' => false, + 'aExpectedFlags' => [ + 'uninstallable' => true, + 'missing' => false, + 'installed' => false, + 'disabled' => true, + 'checked' => true, + ], + ], + 'A mandatory extension should be checked and disabled even if the "disable uninstallation check" flag is set' => [ + 'aExtensionsOnDiskOrDb' => [ + 'itop-ext1' => [ + 'installed' => false, + ], + ], + 'aWizardStepDefinition' => [ + 'extension_code' => 'itop-ext1', + 'mandatory' => true, + 'uninstallable' => true, + ], + 'bCurrentSelected' => false, + 'bDisableUninstallChecks' => true, + 'aExpectedFlags' => [ + 'uninstallable' => true, + 'missing' => false, + 'installed' => false, + 'disabled' => true, + 'checked' => true, + ], + ], + 'An optional sub extension should not force its parent flags' => [ + 'aExtensionsOnDiskOrDb' => [ + 'itop-ext1' => [ + 'installed' => false, + ], + 'itop-ext1-1' => [ + 'installed' => false, + ], + ], + 'aWizardStepDefinition' => [ + 'extension_code' => 'itop-ext1', + 'mandatory' => false, + 'uninstallable' => true, + 'sub_options' => [ + 'options' => [ + [ + 'extension_code' => 'itop-ext1-1', + 'mandatory' => false, + 'uninstallable' => true, + ], + ], + ], + ], + 'bCurrentSelected' => false, + 'bDisableUninstallChecks' => false, + 'aExpectedFlags' => [ + 'uninstallable' => true, + 'missing' => false, + 'installed' => false, + 'disabled' => false, + 'checked' => false, + ], + ], + 'A mandatory sub extension should force its parent to be checked and disabled' => [ + 'aExtensionsOnDiskOrDb' => [ + 'itop-ext1' => [ + 'installed' => false, + ], + 'itop-ext1-1' => [ + 'installed' => false, + ], + ], + 'aWizardStepDefinition' => [ + 'extension_code' => 'itop-ext1', + 'mandatory' => false, + 'uninstallable' => true, + 'sub_options' => [ + 'options' => [ + [ + 'extension_code' => 'itop-ext1-1', + 'mandatory' => true, + 'uninstallable' => true, + ], + ], + ], + ], + 'bCurrentSelected' => false, + 'bDisableUninstallChecks' => false, + 'aExpectedFlags' => [ + 'uninstallable' => true, + 'missing' => false, + 'installed' => false, + 'disabled' => true, + 'checked' => true, + ], + ], + 'An installed non uninstallable sub extension should force its parent to be checked and disabled' => [ + 'aExtensionsOnDiskOrDb' => [ + 'itop-ext1' => [ + 'installed' => true, + ], + 'itop-ext1-1' => [ + 'installed' => true, + ], + ], + 'aWizardStepDefinition' => [ + 'extension_code' => 'itop-ext1', + 'mandatory' => false, + 'uninstallable' => true, + 'sub_options' => [ + 'options' => [ + [ + 'extension_code' => 'itop-ext1-1', + 'mandatory' => false, + 'uninstallable' => false, + ], + ], + ], + ], + 'bCurrentSelected' => false, + 'bDisableUninstallChecks' => false, + 'aExpectedFlags' => [ + 'uninstallable' => true, + 'missing' => false, + 'installed' => true, + 'disabled' => true, + 'checked' => true, + ], + ], + 'A non installed non uninstallable sub extension should not force its parent flags' => [ + 'aExtensionsOnDiskOrDb' => [ + 'itop-ext1' => [ + 'installed' => true, + ], + 'itop-ext1-1' => [ + 'installed' => false, + ], + ], + 'aWizardStepDefinition' => [ + 'extension_code' => 'itop-ext1', + 'mandatory' => false, + 'uninstallable' => true, + 'sub_options' => [ + 'options' => [ + [ + 'extension_code' => 'itop-ext1-1', + 'mandatory' => false, + 'uninstallable' => false, + ], + ], + ], + ], + 'bCurrentSelected' => false, + 'bDisableUninstallChecks' => false, + 'aExpectedFlags' => [ + 'uninstallable' => true, + 'missing' => false, + 'installed' => true, + 'disabled' => false, + 'checked' => false, + ], + ], + ]; + } + + /** + * @dataProvider ProviderComputeChoiceFlags + */ + public function testComputeChoiceFlags($aExtensionsOnDiskOrDb, $aWizardStepDefinition, $bIsCurrentSelected, $bDisableUninstallChecks, $aExpectedFlags) + { + $this->oWizStepModulesChoiceFake->setExtensionMap(iTopExtensionsMapFake::createFromArray($aExtensionsOnDiskOrDb)); + $aFlags = $this->oWizStepModulesChoiceFake->ComputeChoiceFlags($aWizardStepDefinition, '_0', $bIsCurrentSelected ? ['_0' => '_0'] : [], false, $bDisableUninstallChecks, true); + $this->assertEquals($aExpectedFlags, $aFlags); + } + + public function ProviderGetAllExtensionsToDisplayInSetupMandatoryFlag() + { + return [ + 'A manually added extension should not be mandatory by default' => [ + 'bExtensionSource' => 'extensions',//iTopExtension::SOURCE_MANUAL + 'bDisableUninstallChecks' => false, + 'bExpectedMandatory' => false, + ], + 'A remotely added extension should be mandatory by default' => [ + 'bExtensionSource' => 'data',//iTopExtension::SOURCE_REMOTE + 'bDisableUninstallChecks' => false, + 'bExpectedMandatory' => true, + ], + 'A remotely added extension should not be mandatory by default if uninstall checks has been disabled' => [ + 'bExtensionSource' => 'data',//iTopExtension::SOURCE_REMOTE + 'bDisableUninstallChecks' => true, + 'bExpectedMandatory' => false, + ], + + ]; + } + + /** + * @dataProvider ProviderGetAllExtensionsToDisplayInSetupMandatoryFlag + */ + public function testGetAllExtensionsToDisplayInSetupMandatoryFlag($bExtensionSource, $bDisableUninstallChecks, $bExpectedMandatory) + { + $aExtensionsOnDiskOrDb = [ + 'itop-ext1' => [ + 'installed' => true, + 'source' => $bExtensionSource, + ], + ]; + $oMap = iTopExtensionsMapFake::createFromArray($aExtensionsOnDiskOrDb); + $aExtensions = $oMap->GetAllExtensionsToDisplayInSetup(false, !$bDisableUninstallChecks); + $this->assertEquals($bExpectedMandatory, $aExtensions['itop-ext1']->bMandatory); + } + + public function ProviderGetAddedAndRemovedExtensions() + { + return [ + 'no extensions' => [ + 'aExtensionsOnDiskOrDb' => [], + + 'aSelected' => [], + 'aExpectedAddedList' => [], + 'aExpectedRemovedList' => [], + ], + 'no extensions added nor removed' => [ + 'aExtensionsOnDiskOrDb' => [ + 'itop-ext1' => [ + 'installed' => false, + ], + ], + 'aSelected' => [], + 'aExpectedAddedList' => [], + 'aExpectedRemovedList' => [], + ], + 'One added extension' => [ + 'aExtensionsOnDiskOrDb' => [ + 'itop-ext1' => [ + 'installed' => false, + ], + ], + 'aSelected' => ['itop-ext1'], + 'aExpectedAddedList' => ['itop-ext1' => 'itop-ext1'], + 'aExpectedRemovedList' => [], + ], + 'One removed extension' => [ + 'aExtensionsOnDiskOrDb' => [ + 'itop-ext1' => [ + 'installed' => true, + ], + ], + 'aSelected' => [], + 'aExpectedAddedList' => [], + 'aExpectedRemovedList' => ['itop-ext1' => 'itop-ext1'], + ], + 'Forced removed extension' => [ + 'aExtensionsOnDiskOrDb' => [ + 'itop-ext1' => [ + 'installed' => true, + 'uninstallable' => false, + ], + ], + 'aSelected' => [], + 'aExpectedAddedList' => [], + 'aExpectedRemovedList' => ['itop-ext1' => 'itop-ext1'], + ], + 'added and removed extensions' => [ + 'aExtensionsOnDiskOrDb' => [ + 'itop-ext-added1' => [ + 'installed' => false, + ], + 'itop-ext-added2' => [ + 'installed' => false, + ], + 'itop-ext-removed1' => [ + 'installed' => true, + ], + 'itop-ext-removed2' => [ + 'installed' => true, + ], + ], + 'aSelected' => ['itop-ext-added1', 'itop-ext-added2'], + 'aExpectedAddedList' => ['itop-ext-added1' => 'itop-ext-added1', 'itop-ext-added2' => 'itop-ext-added2'], + 'aExpectedRemovedList' => ['itop-ext-removed1' => 'itop-ext-removed1', 'itop-ext-removed2' => 'itop-ext-removed2'], + ], + + ]; + } + + /** + * @dataProvider ProviderGetAddedAndRemovedExtensions + */ + public function testGetAddedAndRemovedExtensions($aExtensionsOnDiskOrDb, $aSelectedExtensions, $aExpectedAddedList, $aExpectedRemovedList) + { + $this->oWizStepModulesChoiceFake->setExtensionMap(iTopExtensionsMapFake::createFromArray($aExtensionsOnDiskOrDb)); + [$aAddedList, $aRemovedList, $aNotUninstallableList] = $this->oWizStepModulesChoiceFake->GetAddedAndRemovedExtensions($aSelectedExtensions); + $this->assertEquals($aExpectedAddedList, $aAddedList); + $this->assertEquals($aExpectedRemovedList, $aRemovedList); + } + + public function testGetStepInfo_PackageWithoutInstallationXML() + { + + $aExtensionsOnDiskOrDb = self::GivenExtensionsOnDisk(); + $oWizStepModulesChoice = $this->GivenWizStepModulesChoiceWithoutXmlInstallation($aExtensionsOnDiskOrDb); + + $expected = [ + 'title' => 'Modules Selection', + 'description' => '

    Select the modules to install. You can launch the installation again to install new modules, but you cannot remove already installed modules.

    ', + 'banner' => '/images/icons/icons8-apps-tab.svg', + 'options' => $aExtensionsOnDiskOrDb, + ]; + + $this->CallAndCheckTwice($oWizStepModulesChoice, null, $expected); + $this->CallAndCheckTwice($oWizStepModulesChoice, 1, null); + } + + private function GivenWizStepModulesChoiceWithoutXmlInstallation(array $aExtensionsOnDiskOrDb): WizStepModulesChoiceFake + { + $oExtensionsMap = $this->createMock(iTopExtensionsMap::class); + $oExtensionsMap->expects($this->once()) + ->method('GetAllExtensionsOptionInfo') + ->willReturn($aExtensionsOnDiskOrDb); + + $oWizard = new WizardController('', ''); + $oWizStepModulesChoice = new WizStepModulesChoiceFake($oWizard, ''); + $oWizStepModulesChoice->setExtensionMap($oExtensionsMap); + + return $oWizStepModulesChoice; + } + + public static function PackageWithInstallationXMLProvider() + { + require_once __DIR__.'/../../../../approot.inc.php'; + require_once APPROOT.'setup/parameters.class.inc.php'; + + $aUsecases = []; + + $aUsecases["[no step] with extensions"] = [ + 'iGetStepInfoIdxArg' => null, + 'expected' => self::GetStep(0), + ]; + + for ($i = 0; $i < 4; $i++) { + $aUsecases["[step $i] with extensions"] = [ + 'iGetStepInfoIdxArg' => $i, + 'expected' => self::GetStep($i), + ]; + } + + $aUsecases["[step 6] with extensions => NO STEP ANYMORE"] = [ + 'iGetStepInfoIdxArg' => 6, + 'expected' => null, + 'iGetAllExtensionsOptionInfoCallCount' => 1, + ]; + + return $aUsecases; + } + + /** + * @dataProvider PackageWithInstallationXMLProvider + */ + public function testGetStepInfo_PackageWithInstallationXMLWithExtensions($iGetStepInfoIdxArg, $expected, $iGetAllExtensionsOptionInfoCallCount = 0) + { + $aExtensionsOnDiskOrDb = self::GivenExtensionsOnDisk(); + $oWizStepModulesChoice = $this->GivenWizStepModulesChoiceWithXmlInstallation($aExtensionsOnDiskOrDb, $iGetAllExtensionsOptionInfoCallCount); + + $this->CallAndCheckTwice($oWizStepModulesChoice, $iGetStepInfoIdxArg, $expected); + } + + public function testGetStepInfo_PackageWithInstallationXML_AfterLastStepWithExtensions() + { + $expected = [ + 'title' => 'Extensions', + 'description' => '

    Select additional extensions to install. You can launch the installation again to install new extensions or remove installed ones.

    ', + 'banner' => '/images/icons/icons8-puzzle.svg', + 'options' => self::GivenExtensionsOnDisk(), + ]; + + $aExtensionsOnDiskOrDb = self::GivenExtensionsOnDisk(); + $oWizStepModulesChoice = $this->GivenWizStepModulesChoiceWithXmlInstallation($aExtensionsOnDiskOrDb, 1); + + $this->CallAndCheckTwice($oWizStepModulesChoice, 5, $expected); + } + + public function testGetStepInfo_PackageWithInstallationXMLAfterLastStepWithoutExtensions() + { + $oWizStepModulesChoice = $this->GivenWizStepModulesChoiceWithXmlInstallation([], 1); + + $this->CallAndCheckTwice($oWizStepModulesChoice, 5, null); + } + + public function testGetStepInfo_PackageWithInstallationXML_MakeSureNextStepIsAlsoCached() + { + $aExtensionsOnDiskOrDb = self::GivenExtensionsOnDisk(); + $oWizStepModulesChoice = $this->GivenWizStepModulesChoiceWithXmlInstallation($aExtensionsOnDiskOrDb, 1); + + $this->CallAndCheckTwice($oWizStepModulesChoice, 4, self::GetStep(4)); + + $expected = [ + 'title' => 'Extensions', + 'description' => '

    Select additional extensions to install. You can launch the installation again to install new extensions or remove installed ones.

    ', + 'banner' => '/images/icons/icons8-puzzle.svg', + 'options' => $aExtensionsOnDiskOrDb, + ]; + $this->CallAndCheckTwice($oWizStepModulesChoice, 5, $expected); + } + + private static function GivenExtensionsOnDisk(): array + { + return [ + 'itop-ext-added1' => [ + 'installed' => false, + ], + 'itop-ext-added2' => [ + 'installed' => false, + ], + ]; + } + + private function GivenWizStepModulesChoiceWithXmlInstallation(array $aExtensionsOnDiskOrDb, $iGetAllExtensionsOptionInfoCallCount): WizStepModulesChoiceFake + { + $oExtensionsMap = $this->createMock(iTopExtensionsMap::class); + $oExtensionsMap->expects($this->exactly($iGetAllExtensionsOptionInfoCallCount)) + ->method('GetAllExtensionsOptionInfo') + ->willReturn($aExtensionsOnDiskOrDb); + + $oWizard = new WizardController('', ''); + //needed to find installation.xml + $oWizard->SetParameter('source_dir', __DIR__.'/ressources'); + $oWizStepModulesChoice = new WizStepModulesChoiceFake($oWizard, ''); + $oWizStepModulesChoice->setExtensionMap($oExtensionsMap); + + return $oWizStepModulesChoice; + } + + private function CallAndCheckTwice($oStep, $iGetStepInfoIdxArg, $expected) + { + $aRes = $this->InvokeNonPublicMethod(WizStepModulesChoiceFake::class, 'GetStepInfo', $oStep, [$iGetStepInfoIdxArg]); + $this->assertEquals($expected, $aRes, "step:".$iGetStepInfoIdxArg); + + $aRes = $this->InvokeNonPublicMethod(WizStepModulesChoiceFake::class, 'GetStepInfo', $oStep, [$iGetStepInfoIdxArg]); + $this->assertEquals($expected, $aRes, "(2nd call) step:".$iGetStepInfoIdxArg); + } + + private static function GetStep($index) + { + $aParams = new XMLParameters(__DIR__.'/ressources/installation.xml'); + $aSteps = $aParams->Get('steps', []); + + return $aSteps[$index] ?? null; + } + + public function ProviderGetSelectedModules() + { + return [ + 'No extension selected' => [ + 'aSelected' => [], + 'aExpectedModules' => [], + 'aExpectedExtensions' => [], + ], + 'One extension selected' => [ + 'aSelected' => ['_0' => '_0'], + 'aExpectedModules' => ['combodo-sample-module' => true], + 'aExpectedExtensions' => ['combodo-sample'], + ], + 'More extensions selected' => [ + 'aSelected' => ['_0' => '_0', '_1' => '_1'], + 'aExpectedModules' => ['combodo-sample-module' => true, 'combodo-test-moduleA' => true, 'combodo-test-moduleB' => true], + 'aExpectedExtensions' => ['combodo-sample', 'combodo-test'], + ], + ]; + } + + /** + * @dataProvider ProviderGetSelectedModules + */ + public function testGetSelectedModules($aSelectedExtensions, $aExpectedModules, $aExpectedExtensions) + { + $aExtensionsMapData = [ + 'combodo-sample' => [ + 'installed' => false, + ], + 'combodo-test' => [ + 'installed' => false, + ], + ]; + $this->oWizStepModulesChoiceFake->setExtensionMap(iTopExtensionsMapFake::createFromArray($aExtensionsMapData)); + + $aStepInfo = [ + 'title' => 'Extensions', + 'description' => '', + 'banner' => '', + 'options' => [ + [ + 'extension_code' => 'combodo-sample', + 'title' => 'Sample extension', + 'description' => '', + 'more_info' => '', + 'default' => true, + 'modules' => [ + 'combodo-sample-module', + ], + 'mandatory' => false, + 'source_label' => '', + 'uninstallable' => true, + 'missing' => false, + ], + [ + 'extension_code' => 'combodo-test', + 'title' => 'Test extension', + 'description' => '', + 'more_info' => '', + 'default' => true, + 'modules' => [ + 'combodo-test-moduleA', + 'combodo-test-moduleB', + ], + 'mandatory' => false, + 'source_label' => '', + 'uninstallable' => true, + 'missing' => false, + ], + ], + ]; + + $aModules = []; + $aExtensions = []; + $this->oWizStepModulesChoiceFake->GetSelectedModules($aStepInfo, $aSelectedExtensions, $aModules, '', '', $aExtensions); + $this->assertEquals($aExpectedModules, $aModules); + $this->assertEquals($aExpectedExtensions, $aExtensions); + } + + public function testGetSelectedModulesShouldAlwaysSelectMandatoryExtension() + { + + $aSelectedExtensions = ['_0' => '_0']; + + $aExtensionsMapData = [ + 'combodo-sample' => [ + 'installed' => true, + ], + ]; + + $this->oWizStepModulesChoiceFake->setExtensionMap(iTopExtensionsMapFake::createFromArray($aExtensionsMapData)); + + $aStepInfo = [ + 'title' => 'Extensions', + 'description' => '', + 'banner' => '', + 'options' => [ + [ + 'extension_code' => 'combodo-sample', + 'title' => 'Sample extension', + 'description' => '', + 'more_info' => '', + 'default' => true, + 'modules' => [ + 'combodo-sample-module', + ], + 'mandatory' => false, + 'source_label' => '', + 'uninstallable' => true, + 'missing' => true, + ], + ], + ]; + + $aExpectedModules = ['combodo-sample-module' => true]; + $aExpectedExtensions = ['combodo-sample']; + + $aModules = []; + $aExtensions = []; + $this->oWizStepModulesChoiceFake->GetSelectedModules($aStepInfo, $aSelectedExtensions, $aModules, '', '', $aExtensions); + $this->assertEquals($aExpectedModules, $aModules); + $this->assertEquals($aExpectedExtensions, $aExtensions); + } + + public function testGetSelectedModulesShouldShouldParseAutoSelectCondition() + { + //the 'auto_select' parameter, contrary to its name, deselect the module if its result is false + + $aSelectedExtensions = ['_0' => '_0']; + + $aExtensionsMapData = [ + 'combodo-sample' => [ + 'installed' => true, + 'module_info' => [ + 'combodo-sample-module' => [ + 'auto_select' => 'true && false', + ], + ], + ], + ]; + $this->oWizStepModulesChoiceFake->setExtensionMap(iTopExtensionsMapFake::createFromArray($aExtensionsMapData)); + + $aStepInfo = [ + 'title' => 'Extensions', + 'description' => '', + 'banner' => '', + 'options' => [ + [ + 'extension_code' => 'combodo-sample', + 'title' => 'Sample extension', + 'description' => '', + 'more_info' => '', + 'default' => true, + 'modules' => [ + 'combodo-sample-module', + ], + 'mandatory' => false, + 'source_label' => '', + 'uninstallable' => true, + 'missing' => true, + ], + ], + ]; + + $aExpectedModules = []; + $aExpectedExtensions = ['combodo-sample']; + + $aModules = []; + $aExtensions = []; + $this->oWizStepModulesChoiceFake->GetSelectedModules($aStepInfo, $aSelectedExtensions, $aModules, '', '', $aExtensions); + $this->assertEquals($aExpectedModules, $aModules); + $this->assertEquals($aExpectedExtensions, $aExtensions); + } + + public function testGetSelectedModulesWithSubOptions() + { + + $aSelectedExtensions = ['_0' => '_0', '_0_0' => '_0_0']; + + $aExtensionsMapData = [ + 'combodo-sample' => [ + 'installed' => false, + ], + 'combodo-sub-sample' => [ + 'installed' => false, + ], + ]; + $this->oWizStepModulesChoiceFake->setExtensionMap(iTopExtensionsMapFake::createFromArray($aExtensionsMapData)); + + $aStepInfo = [ + 'options' => [ + [ + 'extension_code' => 'combodo-sample', + 'title' => 'Sample extension', + 'description' => '', + 'more_info' => '', + 'default' => true, + 'modules' => [ + 'combodo-sample-module', + ], + 'mandatory' => false, + 'source_label' => '', + 'uninstallable' => true, + 'missing' => false, + 'sub_options' => [ + 'options' => [ + [ + 'extension_code' => 'combodo-sub-sample', + 'title' => 'Sample sub extension', + 'description' => '', + 'more_info' => '', + 'default' => true, + 'modules' => [ + 'combodo-sub-sample-module', + ], + 'mandatory' => false, + 'source_label' => '', + 'uninstallable' => true, + 'missing' => false, + ], + ], + ], + ], + ], + ]; + + $aExpectedModules = ['combodo-sample-module' => true, 'combodo-sub-sample-module' => true]; + $aExpectedExtensions = ['combodo-sample', 'combodo-sub-sample']; + + $aModules = []; + $aExtensions = []; + $this->oWizStepModulesChoiceFake->GetSelectedModules($aStepInfo, $aSelectedExtensions, $aModules, '', '', $aExtensions); + $this->assertEquals($aExpectedModules, $aModules); + $this->assertEquals($aExpectedExtensions, $aExtensions); + } + + public function testGetSelectedModulesShouldThrowAnExceptionWhenAnySelectedExtensionDoesNotHaveAnyAssociatedModules() + { + $aExtensionsMapData = [ + 'combodo-sample' => [ + 'installed' => false, + ], + ]; + $this->oWizStepModulesChoiceFake->setExtensionMap(iTopExtensionsMapFake::createFromArray($aExtensionsMapData)); + + //GetSelectedModules + $aStepInfo = [ + 'title' => 'Extensions', + 'description' => '', + 'banner' => '', + 'options' => [ + [ + 'extension_code' => 'combodo-sample', + 'title' => 'Sample extension', + 'description' => '', + 'more_info' => '', + 'default' => true, + 'modules' => [], + 'mandatory' => false, + 'source_label' => '', + 'uninstallable' => true, + 'missing' => false, + ], + ], + ]; + + $aModules = []; + $aExtensions = []; + $this->expectException('Exception'); + $this->expectExceptionMessage('Extension combodo-sample does not have any module associated'); + $this->oWizStepModulesChoiceFake->GetSelectedModules($aStepInfo, ['_0' => '_0'], $aModules, '', '', $aExtensions); + } + + public function testGetSelectedModulesShouldNotThrowAnExceptionWhenAMandatoryModuleIsMissing() + { + $aExtensionsMapData = []; + $this->oWizStepModulesChoiceFake->setExtensionMap(iTopExtensionsMapFake::createFromArray($aExtensionsMapData)); + + //GetSelectedModules + $aStepInfo = [ + 'title' => 'Extensions', + 'description' => '', + 'banner' => '', + 'options' => [ + [ + 'extension_code' => 'combodo-sample', + 'title' => 'Sample extension', + 'description' => '', + 'more_info' => '', + 'default' => true, + 'modules' => [], + 'mandatory' => true, + 'source_label' => '', + 'uninstallable' => true, + 'missing' => true, + ], + ], + ]; + + $aModules = []; + $aExtensions = []; + $this->oWizStepModulesChoiceFake->GetSelectedModules($aStepInfo, ['_0' => '_0'], $aModules, '', '', $aExtensions); + $this->assertCount(0, $aModules); + $this->assertCount(1, $aExtensions); + + } + + public function ProviderDisplayOptions() + { + return [ + 'no choices' => [ + 'aStepOptions' => [], + 'aStepAlternatives' => [], + + 'aSelectedComponents' => [], + 'aDefaults' => [], + 'aExpectedHTML' => '', + ], + 'one not installed extension' => [ + 'aStepOptions' => [ + [ + 'extension_code' => 'itop-ext-not-installed', + 'title' => 'My extension', + 'description' => 'Do something', + 'more_info' => '', + 'modules' => [], + 'mandatory' => false, + 'source_label' => 'Local extensions folder', + 'uninstallable' => true, + 'missing' => false, + 'version' => '1.2.3', + ], + ], + 'aStepAlternatives' => [], + + 'aSelectedComponents' => [], + 'aDefaults' => [], + 'aExpectedHTML' => << +
    + + +
    +
    +
    + + +
    to be installed
    not installed
    +
    + +
    + Do something + +
    +
    + + +HTML, + ], + 'one installed extension' => [ + 'aStepOptions' => [ + [ + 'extension_code' => 'itop-ext-installed', + 'title' => 'My extension', + 'description' => 'Do something', + 'more_info' => '', + 'modules' => [], + 'mandatory' => false, + 'source_label' => 'Local extensions folder', + 'uninstallable' => true, + 'missing' => false, + 'version' => '1.2.3', + ], + ], + 'aStepAlternatives' => [], + + 'aSelectedComponents' => [], + 'aDefaults' => [], + 'aExpectedHTML' => << +
    + + +
    +
    +
    + + +
    installed
    to be uninstalled
    +
    + +
    + Do something + +
    +
    + + +HTML, + ], + + 'one installed extension that cannot be uninstalled' => [ + 'aStepOptions' => [ + [ + 'extension_code' => 'itop-ext-installed', + 'title' => 'My extension', + 'description' => 'Do something', + 'more_info' => '', + 'modules' => [], + 'mandatory' => false, + 'source_label' => 'Local extensions folder', + 'uninstallable' => false, + 'missing' => false, + 'version' => '1.2.3', + ], + ], + 'aStepAlternatives' => [], + + 'aSelectedComponents' => [], + 'aDefaults' => [], + 'aExpectedHTML' => << +
    + + +
    +
    +
    + + +
    installed
    to be uninstalled
    cannot be uninstalled
    +
    + +
    + Do something + +
    +
    + + +HTML, + ], + 'one mandatory extension' => [ + 'aStepOptions' => [ + [ + 'extension_code' => 'itop-ext-not-installed', + 'title' => 'My extension', + 'description' => 'Do something', + 'more_info' => '', + 'modules' => [], + 'mandatory' => true, + 'source_label' => 'Local extensions folder', + 'uninstallable' => true, + 'missing' => false, + 'version' => '1.2.3', + ], + ], + 'aStepAlternatives' => [], + + 'aSelectedComponents' => [], + 'aDefaults' => [], + 'aExpectedHTML' => << +
    + + +
    +
    +
    + + +
    to be installed
    not installed
    +
    + +
    + Do something + +
    +
    + + +HTML, + ], + 'one choice alternative' => [ + 'aStepOptions' => [], + 'aStepAlternatives' => [ + [ + 'extension_code' => 'itop-alt-nothing', + 'title' => 'No Change', + 'description' => 'Do nothing', + 'modules' => [], + ], + ], + + 'aSelectedComponents' => [], + 'aDefaults' => [], + 'aExpectedHTML' => << +
    + + +
    +
    +
    + + +
    to be installed
    not installed
    +
    + +
    + Do nothing + +
    +
    + + +HTML, + ], + 'two choices alternative with non-empty installed' => [ + 'aStepOptions' => [], + 'aStepAlternatives' => [ + [ + 'extension_code' => 'itop-alt-something', + 'title' => 'Change', + 'description' => 'I am something', + 'modules' => [ + 'itop-alt-module', + ], + ], + [ + 'extension_code' => 'itop-alt-nothing', + 'title' => 'No Change', + 'description' => 'Do nothing', + 'modules' => [], + ], + ], + + 'aSelectedComponents' => [], + 'aDefaults' => [], + 'aExpectedHTML' => << +
    + + +
    +
    +
    + + +
    installed
    to be uninstalled
    +
    + +
    + I am something + +
    +
    + + +
    +
    + + +
    +
    +
    + + +
    to be installed
    not installed
    +
    + +
    + Do nothing + +
    +
    +
    + +HTML, + ], + 'two choices with sub options' => [ + 'aStepOptions' => [], + 'aStepAlternatives' => [ + [ + 'extension_code' => 'itop-alt-something', + 'title' => 'Change', + 'description' => 'I am something', + 'modules' => [], + 'sub_options' => [ + 'options' => [ + [ + 'extension_code' => 'itop-ext-not-installed', + 'title' => 'My extension', + 'description' => 'Do something', + 'more_info' => '', + 'modules' => [], + 'mandatory' => false, + //'source_label' => '', + 'uninstallable' => true, + 'missing' => false, + //'version' => '1.2.3', + ], + ], + ], + ], + [ + 'extension_code' => 'itop-alt-nothing', + 'title' => 'No Change', + 'description' => 'Do nothing', + 'modules' => [], + ], + ], + + 'aSelectedComponents' => [], + 'aDefaults' => [], + 'aExpectedHTML' => << +
    + + +
    +
    +
    + + +
    installed
    to be uninstalled
    +
    + +
    + I am something +
    +
    +
    + + +
    +
    +
    + + +
    to be installed
    not installed
    +
    + +
    + Do something + +
    +
    +
    +
    +
    +
    + + +
    +
    + + +
    +
    +
    + + +
    to be installed
    not installed
    +
    + +
    + Do nothing + +
    +
    +
    + +HTML, + ], + + ]; + } + + /** + * @dataProvider ProviderDisplayOptions + */ + public function testDisplayOptions($aStepOptions, $aStepAlternatives, $aSelectedComponents, $aDefaults, $sExpectedHTML) + { + $aExtensionsOnDiskOrDb = [ + 'itop-ext-not-installed' => [ + 'installed' => false, + ], + 'itop-ext-installed' => [ + 'installed' => true, + ], + 'itop-alt-nothing' => [ + 'installed' => false, + ], + 'itop-alt-something' => [ + 'installed' => true, + ], + ]; + $this->oWizStepModulesChoiceFake->setExtensionMap(iTopExtensionsMapFake::createFromArray($aExtensionsOnDiskOrDb)); + $aStepInfo = [ + 'options' => $aStepOptions, + 'alternatives' => $aStepAlternatives, + ]; + $oPage = new \WebPageFake(); + + $this->oWizStepModulesChoiceFake->DisplayOptions($oPage, $aStepInfo, $aSelectedComponents, $aDefaults); + + $this->assertEquals($sExpectedHTML, $oPage->sContent); + } + + public function testGetSelectedComponents() + { + $aParams = new XMLParameters(__DIR__.'/ressources/installation_330.xml'); + $aSteps = $aParams->Get('steps', []); + + $aSelectedExtensions = ["itop-config-mgmt-core","itop-config-mgmt-datacenter","itop-config-mgmt-end-user","itop-config-mgmt-storage","itop-config-mgmt-virtualization","itop-container-mgmt","itop-service-mgmt-enterprise","itop-ticket-mgmt-simple-ticket","itop-ticket-mgmt-simple-ticket-enhanced-portal","itop-change-mgmt-simple","itop-kown-error-mgmt","itop-problem-mgmt","combodo-oauth2-client","combodo-mfa-extended","combodo-data-replication","combodo-api-playground","combodo-snapshot"]; + $aRes = $this->oWizStepModulesChoiceFake->GetSelectedComponents($aSteps, json_encode($aSelectedExtensions)); + + $aExpected = json_decode('[{"_0":"_0","_1":"_1","_2":"_2","_3":"_3","_4":"_4","_4_0":"_4_0"},{"_0":"_0"},{"_0":"_0","_0_0":"_0_0"},{"_0":"_0"},{"_0":"_0","_1":"_1"}]', true); + $this->assertEquals($aExpected, $aRes); + } + + public function testGetWizardSteps() + { + $this->oWizard->SetParameter('source_dir', __DIR__.'/ressources'); + $aExtensionsOnDiskOrDb = [ + 'itop-ext-not-installed' => [ + 'installed' => false, + ], + 'itop-ext-installed' => [ + 'installed' => true, + ], + ]; + $this->oWizStepModulesChoiceFake->setExtensionMap(iTopExtensionsMapFake::createFromArray($aExtensionsOnDiskOrDb)); + + $expected = [ + ["class" => "WizStepWelcome","state" => ""], + ["class" => "WizStepInstallOrUpgrade","state" => ""], + ["class" => "WizStepDetectedInfo","state" => ""], + ["class" => "WizStepUpgradeMiscParams","state" => ""], + ]; + + for ($i = 0;$i <= 5; $i++) { + $expected [] = ["class" => "WizStepModulesChoice","state" => "".$i]; + } + $this->assertEquals($expected, $this->oWizStepModulesChoiceFake->GetWizardSteps()); + } + + public function testGetWizardStepsWithoutAnyExtension() + { + $this->oWizard->SetParameter('source_dir', __DIR__.'/ressources'); + $oExtensionMap = $this->createMock(iTopExtensionsMap::class); + $oExtensionMap->expects(self::any())->method('GetAllExtensionsOptionInfo')->willReturn([]); + + $this->oWizStepModulesChoiceFake->setExtensionMap($oExtensionMap); + + $expected = [ + ["class" => "WizStepWelcome","state" => ""], + ["class" => "WizStepInstallOrUpgrade","state" => ""], + ["class" => "WizStepDetectedInfo","state" => ""], + ["class" => "WizStepUpgradeMiscParams","state" => ""], + ]; + + for ($i = 0;$i <= 4; $i++) { + $expected [] = ["class" => "WizStepModulesChoice","state" => "".$i]; + } + $this->assertEquals($expected, $this->oWizStepModulesChoiceFake->GetWizardSteps()); + } +} diff --git a/tests/php-unit-tests/unitary-tests/setup/feature_removal/ModelSerializationTest.php b/tests/php-unit-tests/unitary-tests/setup/feature_removal/ModelSerializationTest.php new file mode 100644 index 0000000000..b671ac9840 --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/feature_removal/ModelSerializationTest.php @@ -0,0 +1,29 @@ +RequireOnceItopFile('/setup/feature_removal/ModelReflectionSerializer.php'); + } + + public function testGetModelFromEnvironment() + { + $aModel = ModelReflectionSerializer::GetInstance()->GetModelFromEnvironment($this->GetTestEnvironment()); + $this->assertEqualsCanonicalizing(MetaModel::GetClasses(), $aModel); + } + + public function testGetModelFromEnvironmentFailure() + { + $this->expectException(\CoreException::class); + $this->expectExceptionMessage("Cannot get classes"); + ModelReflectionSerializer::GetInstance()->GetModelFromEnvironment('gabuzomeu'); + } +} diff --git a/tests/php-unit-tests/unitary-tests/setup/feature_removal/SetupAuditTest.php b/tests/php-unit-tests/unitary-tests/setup/feature_removal/SetupAuditTest.php new file mode 100644 index 0000000000..c9efefa4bf --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/feature_removal/SetupAuditTest.php @@ -0,0 +1,133 @@ +oEnvironment = new UnitTestRunTimeEnvironment(self::ENVT); + $this->oEnvironment->bUseDelta = false; + $this->oEnvironment->bUseAdditionalFeatures = true; + parent::setUp(); + + $this->RequireOnceItopFile('/setup/feature_removal/SetupAudit.php'); + $this->RequireOnceItopFile('/setup/feature_removal/InplaceSetupAudit.php'); + $this->RequireOnceItopFile('/setup/feature_removal/DryRemovalRuntimeEnvironment.php'); + } + + public function GetTestEnvironment(): string + { + return self::ENVT; + } + + public function testComputeDryRemoval() + { + $oDryRemovalRuntimeEnvt = new DryRemovalRuntimeEnvironment($this->GetTestEnvironment(), ['nominal_ext1', 'finalclass_ext2']); + $oDryRemovalRuntimeEnvt->CompileFrom($this->GetTestEnvironment()); + + $oSetupAudit = new SetupAudit($this->GetTestEnvironment()); + + $expected = [ + "Feature1Module1MyClass", + "FinalClassFeature2Module1MyClass", + "FinalClassFeature2Module1MyFinalClassFromLocation", + ]; + $this->assertEqualsCanonicalizing($expected, $oSetupAudit->GetRemovedClasses()); + + $expected = [ + "FinalClassFeature2Module1MyFinalClassFromLocation" => 0, + ]; + $this->assertEqualsCanonicalizing($expected, $oSetupAudit->RunDataAudit()); + } + + public function testGetRemovedClassesFromSetupWizard() + { + $sEnv = MetaModel::GetEnvironment(); + + $aClassesBeforeRemoval = ModelReflectionSerializer::GetInstance()->GetModelFromEnvironment($sEnv); + $aClassesBeforeRemoval[] = "GabuZomeu"; + + $oSetupAudit = new InplaceSetupAudit($aClassesBeforeRemoval, $sEnv); + $oSetupAudit->ComputeClasses(); + $this->assertEquals(["GabuZomeu"], $oSetupAudit->GetRemovedClasses()); + } + + public function testGetIssues() + { + $sUID = "AuditExtensionsCleanupRules_".uniqid(); + $oOrg = $this->CreateOrganization($sUID); + $this->createObject('FinalClassFeature1Module1MyFinalClassFromLocation', ['org_id' => $oOrg->GetKey(), 'name' => $sUID, 'name2' => uniqid()]); + + $oSetupAudit = new SetupAudit(MetaModel::GetEnvironment()); + $aRemovedClasses = [ + "Feature1Module1MyClass", + "FinalClassFeature1Module1MyClass", + "FinalClassFeature1Module1MyFinalClassFromLocation", + "FinalClassFeature2Module1MyClass", + "FinalClassFeature2Module1MyFinalClassFromLocation", + ]; + + //avoid setup dry computation + $this->SetNonPublicProperty($oSetupAudit, 'aRemovedClasses', $aRemovedClasses); + + $expected = [ + "FinalClassFeature1Module1MyFinalClassFromLocation" => 1, + "FinalClassFeature2Module1MyFinalClassFromLocation" => 0, + ]; + $this->assertEqualsCanonicalizing($expected, $oSetupAudit->RunDataAudit()); + } + + public function testAuditExtensionsCleanupRulesFailASAP() + { + $sUID = "AuditExtensionsCleanupRules_".uniqid(); + $oOrg = $this->CreateOrganization($sUID); + $this->createObject('FinalClassFeature1Module1MyFinalClassFromLocation', ['org_id' => $oOrg->GetKey(), 'name' => $sUID, 'name2' => uniqid()]); + $this->createObject('FinalClassFeature2Module1MyFinalClassFromLocation', ['org_id' => $oOrg->GetKey(), 'name' => $sUID, 'name2' => uniqid()]); + + $oSetupAudit = new SetupAudit(MetaModel::GetEnvironment()); + $aRemovedClasses = [ + "Feature1Module1MyClass", + "FinalClassFeature1Module1MyClass", + "FinalClassFeature1Module1MyFinalClassFromLocation", + "FinalClassFeature2Module1MyClass", + "FinalClassFeature2Module1MyFinalClassFromLocation", + ]; + + //avoid setup dry computation + $this->SetNonPublicProperty($oSetupAudit, 'aRemovedClasses', $aRemovedClasses); + + $expected = [ + "FinalClassFeature1Module1MyFinalClassFromLocation" => 1, + ]; + $this->assertEqualsCanonicalizing($expected, $oSetupAudit->RunDataAudit(true)); + } +} diff --git a/tests/php-unit-tests/unitary-tests/setup/feature_removal/additional_features/finalclass_ext1/extension.xml b/tests/php-unit-tests/unitary-tests/setup/feature_removal/additional_features/finalclass_ext1/extension.xml new file mode 100644 index 0000000000..492f493191 --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/feature_removal/additional_features/finalclass_ext1/extension.xml @@ -0,0 +1,22 @@ + + + finalclass_ext1 + Combodo SARL + + + + 6.6.6 + + + finalclass_ext1_module1 + tags/6.6.6 + + + 2023-07-19 + + 3.2.0 + + false + + \ No newline at end of file diff --git a/tests/php-unit-tests/unitary-tests/setup/feature_removal/additional_features/finalclass_ext1/finalclass_ext1_module1/datamodel.finalclass_ext1_module1.xml b/tests/php-unit-tests/unitary-tests/setup/feature_removal/additional_features/finalclass_ext1/finalclass_ext1_module1/datamodel.finalclass_ext1_module1.xml new file mode 100644 index 0000000000..9b34614160 --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/feature_removal/additional_features/finalclass_ext1/finalclass_ext1_module1/datamodel.finalclass_ext1_module1.xml @@ -0,0 +1,76 @@ + + + + + + + bizmodel,searchable + false + FinalClassFeature1Module1MyFinalClassFromLocation + + + + + + + + + + + + + + + + + + + + + name2 + + false + + + + + Location + + + + bizmodel,searchable + false + FinalClassFeature1Module1MyClass + + + + + + + + + + + + + + + + + + + name + + false + + + + + + cmdbAbstractObject + + + + + + \ No newline at end of file diff --git a/tests/php-unit-tests/unitary-tests/setup/feature_removal/additional_features/finalclass_ext1/finalclass_ext1_module1/model.finalclass_ext1_module1.php b/tests/php-unit-tests/unitary-tests/setup/feature_removal/additional_features/finalclass_ext1/finalclass_ext1_module1/model.finalclass_ext1_module1.php new file mode 100644 index 0000000000..acf219fa12 --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/feature_removal/additional_features/finalclass_ext1/finalclass_ext1_module1/model.finalclass_ext1_module1.php @@ -0,0 +1,16 @@ + 'Ext For Test', + 'category' => 'business', + + // Setup + // + 'dependencies' => [ + 'itop-structure/3.2.0', + ], + 'mandatory' => false, + 'visible' => true, + 'installer' => '', + + // Components + // + 'datamodel' => [ + 'model.finalclass_ext1_module1.php', + ], + 'webservice' => [], + 'data.struct' => [// add your 'structure' definition XML files here, + ], + 'data.sample' => [// add your sample data XML files here, + ], + + // Documentation + // + 'doc.manual_setup' => '', // hyperlink to manual setup documentation, if any + 'doc.more_information' => '', // hyperlink to more information, if any + + // Default settings + // + 'settings' => [// Module specific settings go here, if any + ], + ] +); diff --git a/tests/php-unit-tests/unitary-tests/setup/feature_removal/additional_features/finalclass_ext2/extension.xml b/tests/php-unit-tests/unitary-tests/setup/feature_removal/additional_features/finalclass_ext2/extension.xml new file mode 100644 index 0000000000..770e595f12 --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/feature_removal/additional_features/finalclass_ext2/extension.xml @@ -0,0 +1,22 @@ + + + finalclass_ext2 + Combodo SARL + + + + 6.6.6 + + + finalclass_ext2_module1 + tags/6.6.6 + + + 2023-07-19 + + 3.2.0 + + false + + \ No newline at end of file diff --git a/tests/php-unit-tests/unitary-tests/setup/feature_removal/additional_features/finalclass_ext2/finalclass_ext2_module1/datamodel.finalclass_ext2_module1.xml b/tests/php-unit-tests/unitary-tests/setup/feature_removal/additional_features/finalclass_ext2/finalclass_ext2_module1/datamodel.finalclass_ext2_module1.xml new file mode 100644 index 0000000000..0fd50aac74 --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/feature_removal/additional_features/finalclass_ext2/finalclass_ext2_module1/datamodel.finalclass_ext2_module1.xml @@ -0,0 +1,76 @@ + + + + + + + bizmodel,searchable + false + FinalClassFeature2Module1MyFinalClassFromLocation + + + + + + + + + + + + + + + + + + + + + name2 + + false + + + + + Location + + + + bizmodel,searchable + false + FinalClassFeature2Module1MyClass + + + + + + + + + + + + + + + + + + + name + + false + + + + + + cmdbAbstractObject + + + + + + \ No newline at end of file diff --git a/tests/php-unit-tests/unitary-tests/setup/feature_removal/additional_features/finalclass_ext2/finalclass_ext2_module1/model.finalclass_ext2_module1.php b/tests/php-unit-tests/unitary-tests/setup/feature_removal/additional_features/finalclass_ext2/finalclass_ext2_module1/model.finalclass_ext2_module1.php new file mode 100644 index 0000000000..acf219fa12 --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/feature_removal/additional_features/finalclass_ext2/finalclass_ext2_module1/model.finalclass_ext2_module1.php @@ -0,0 +1,16 @@ + 'Ext For Test', + 'category' => 'business', + + // Setup + // + 'dependencies' => [ + 'itop-structure/3.2.0', + ], + 'mandatory' => false, + 'visible' => true, + 'installer' => '', + + // Components + // + 'datamodel' => [ + 'model.finalclass_ext2_module1.php', + ], + 'webservice' => [], + 'data.struct' => [// add your 'structure' definition XML files here, + ], + 'data.sample' => [// add your sample data XML files here, + ], + + // Documentation + // + 'doc.manual_setup' => '', // hyperlink to manual setup documentation, if any + 'doc.more_information' => '', // hyperlink to more information, if any + + // Default settings + // + 'settings' => [// Module specific settings go here, if any + ], + ] +); diff --git a/tests/php-unit-tests/unitary-tests/setup/feature_removal/additional_features/nominal_ext1/extension.xml b/tests/php-unit-tests/unitary-tests/setup/feature_removal/additional_features/nominal_ext1/extension.xml new file mode 100644 index 0000000000..6d186e699d --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/feature_removal/additional_features/nominal_ext1/extension.xml @@ -0,0 +1,22 @@ + + + nominal_ext1 + Combodo SARL + + + + 6.6.6 + + + nominal_ext1_module1 + tags/6.6.6 + + + 2023-07-19 + + 3.2.0 + + false + + \ No newline at end of file diff --git a/tests/php-unit-tests/unitary-tests/setup/feature_removal/additional_features/nominal_ext1/nominal_ext1_module1/datamodel.nominal_ext1_module1.xml b/tests/php-unit-tests/unitary-tests/setup/feature_removal/additional_features/nominal_ext1/nominal_ext1_module1/datamodel.nominal_ext1_module1.xml new file mode 100644 index 0000000000..8f3a113db9 --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/feature_removal/additional_features/nominal_ext1/nominal_ext1_module1/datamodel.nominal_ext1_module1.xml @@ -0,0 +1,42 @@ + + + + + + + bizmodel,searchable + false + Feature1Module1MyClass + + + + + + + + + + + + + + + + + + + name + + false + + + + + + cmdbAbstractObject + + + + + + \ No newline at end of file diff --git a/tests/php-unit-tests/unitary-tests/setup/feature_removal/additional_features/nominal_ext1/nominal_ext1_module1/model.nominal_ext1_module1.php b/tests/php-unit-tests/unitary-tests/setup/feature_removal/additional_features/nominal_ext1/nominal_ext1_module1/model.nominal_ext1_module1.php new file mode 100644 index 0000000000..acf219fa12 --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/feature_removal/additional_features/nominal_ext1/nominal_ext1_module1/model.nominal_ext1_module1.php @@ -0,0 +1,16 @@ + 'Ext For Test', + 'category' => 'business', + + // Setup + // + 'dependencies' => [ + 'itop-structure/3.2.0', + ], + 'mandatory' => false, + 'visible' => true, + 'installer' => '', + + // Components + // + 'datamodel' => [ + 'model.nominal_ext1_module1.php', + ], + 'webservice' => [], + 'data.struct' => [// add your 'structure' definition XML files here, + ], + 'data.sample' => [// add your sample data XML files here, + ], + + // Documentation + // + 'doc.manual_setup' => '', // hyperlink to manual setup documentation, if any + 'doc.more_information' => '', // hyperlink to more information, if any + + // Default settings + // + 'settings' => [// Module specific settings go here, if any + ], + ] +); diff --git a/tests/php-unit-tests/unitary-tests/setup/iTopExtensionTest.php b/tests/php-unit-tests/unitary-tests/setup/iTopExtensionTest.php new file mode 100644 index 0000000000..f78db99782 --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/iTopExtensionTest.php @@ -0,0 +1,69 @@ +RequireOnceItopFile('/setup/unattended-install/InstallationFileService.php'); + ModuleDiscovery::ResetCache(); + } + + public function testCanBeUninstalledDefaultValueIsTrue() + { + $oExtension = new iTopExtension(); + $this->assertTrue($oExtension->CanBeUninstalled(), 'An extension should be uninstallable by default.'); + } + + public function testCanBeUninstalledReturnTrueWhenAllModulesCanBeUninstalled() + { + $oExtension = new iTopExtension(); + $oExtension->aModuleInfo['combodo-test-yes1'] = [ + 'uninstallable' => 'yes', + ]; + $oExtension->aModuleInfo['combodo-test-yes2'] = [ + 'uninstallable' => 'yes', + ]; + $this->assertTrue($oExtension->CanBeUninstalled(), 'An extension should be considered uninstallable if all of its modules are uninstallable.'); + } + + public function testCanBeUninstalledReturnFalseWhenAtLeastOneModuleCannotBeUninstalled() + { + $oExtension = new iTopExtension(); + $oExtension->aModuleInfo['combodo-test-yes'] = [ + 'uninstallable' => 'yes', + ]; + $oExtension->aModuleInfo['combodo-test-no'] = [ + 'uninstallable' => 'no', + ]; + $this->assertFalse($oExtension->CanBeUninstalled(), 'An extension should be considered non-uninstallable if at least one of its modules is not uninstallable.'); + } + + public function testCanBeUninstalledAnyValueDifferentThanYesIsConsideredFalse() + { + $oExtension = new iTopExtension(); + $oExtension->aModuleInfo['combodo-test-maybe'] = [ + 'uninstallable' => 'maybe', + ]; + $this->assertFalse($oExtension->CanBeUninstalled(), 'Any value in the uninstallable flag different than yes should be considered false.'); + } + + public function testCanBeUninstalledExtensionValueOverwriteModulesValue() + { + $oExtension = new iTopExtension(); + $oExtension->bCanBeUninstalled = true; + $oExtension->aModuleInfo['combodo-test-no'] = [ + 'uninstallable' => 'no', + ]; + $this->assertTrue($oExtension->CanBeUninstalled(), 'The uninstallable flag provided in the extension should prevail over those defined in the modules.'); + + $oExtension = new iTopExtension(); + $oExtension->bCanBeUninstalled = false; + $oExtension->aModuleInfo['combodo-test-yes'] = [ + 'uninstallable' => 'yes', + ]; + $this->assertFalse($oExtension->CanBeUninstalled(), 'The uninstallable flag provided in the extension should prevail over those defined in the modules.'); + } +} diff --git a/tests/php-unit-tests/unitary-tests/setup/iTopExtensionsMapFake.php b/tests/php-unit-tests/unitary-tests/setup/iTopExtensionsMapFake.php new file mode 100644 index 0000000000..8dbf59085c --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/iTopExtensionsMapFake.php @@ -0,0 +1,30 @@ +aExtensions = []; + $this->aExtensionsByCode = []; + $this->aScannedDirs = []; + } + + public static function createFromArray($aExtensions) + { + $oMap = new static(); + + foreach ($aExtensions as $sCode => $aExtension) { + $oExtension = new iTopExtension(); + $oExtension->sCode = $sCode; + $oExtension->sLabel = $sCode; + $oExtension->bInstalled = $aExtension['installed']; + $oExtension->aModules = $aExtension['modules'] ?? []; + $oExtension->bCanBeUninstalled = $aExtension['uninstallable'] ?? null; + $oExtension->sVersion = $aExtension['version'] ?? '1.0.0'; + $oExtension->sSource = $aExtension['source'] ?? iTopExtension::SOURCE_MANUAL; + $oExtension->aModuleInfo = $aExtension['module_info'] ?? []; + $oMap->AddExtension($oExtension); + } + return $oMap; + } +} diff --git a/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/AnalyzeInstallationTest.php b/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/AnalyzeInstallationTest.php new file mode 100644 index 0000000000..3d855e69dd --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/AnalyzeInstallationTest.php @@ -0,0 +1,162 @@ +RequireOnceItopFile('setup/modulediscovery.class.inc.php'); + $this->RequireOnceItopFile('setup/runtimeenv.class.inc.php'); + } + + public static function AnalyzeInstallationProvider() + { + //$aModules = json_decode(file_get_contents(__DIR__.'/ressources/priv_modules.json'), true); + $aAnalyzeInstallationOutput = json_decode(file_get_contents(__DIR__.'/ressources/analyze_installation_output.json'), true); + $aAvailableModules = json_decode(file_get_contents(__DIR__.'/ressources/available_modules.json'), true); + return [ + 'new modules not in DB setup history' => [ + 'aAvailableModules' => [ + 'mandatory_module/1.0.0' => [ + "mandatory" => true, + "ga" => "bu", + ], + 'optional_module/6.6.6' => [ + "mandatory" => false, + "zo" => "meu", + ], + ], + 'aInstalledModules' => [], + 'expected' => [ + '_Root_' => [ + 'installed_version' => '', + 'available_version' => 'ITOP_VERSION_FULL', + 'name_code' => 'ITOP_APPLICATION', + ], + 'mandatory_module' => [ + "mandatory" => true, + 'installed_version' => '', + 'available_version' => '1.0.0', + 'install' => [ + 'flag' => 2, + 'message' => 'the module is part of the application', + ], + "ga" => "bu", + ], + 'optional_module' => [ + "mandatory" => false, + 'installed_version' => '', + 'available_version' => '6.6.6', + "zo" => "meu", + 'install' => [ + 'flag' => 1, + 'message' => '', + ], + ], + ], + ], + 'new modules ALREADY in DB setup history' => [ + 'aAvailableModules' => [ + 'mandatory_module/1.0.0' => [ + "mandatory" => true, + "ga" => "bu", + ], + 'optional_module/6.6.6' => [ + "mandatory" => false, + "zo" => "meu", + ], + ], + 'aInstalledModules' => json_decode(file_get_contents(__DIR__.'/ressources/priv_modules_simpleusecase.json'), true), + 'expected' => [ + '_Root_' => [ + 'installed_version' => '3.3.0-dev-svn', + 'available_version' => 'ITOP_VERSION_FULL', + 'name_code' => 'ITOP_APPLICATION', + ], + 'mandatory_module' => [ + "mandatory" => true, + 'installed_version' => '3.3.0', + 'available_version' => '1.0.0', + "ga" => "bu", + 'install' => [ + 'flag' => 2, + 'message' => 'the module is part of the application', + ], + 'uninstall' => [ + 'flag' => 3, + 'message' => 'the module is part of the application', + ], + ], + 'optional_module' => [ + "mandatory" => false, + 'installed_version' => '3.3.0', + 'available_version' => '6.6.6', + "zo" => "meu", + 'install' => [ + 'flag' => 1, + 'message' => '', + ], + 'uninstall' => [ + 'flag' => 1, + 'message' => '', + ], + ], + ], + ], + 'dummyfirst installation' => [ + 'aAvailableModules' => [], + 'aInstalledModules' => [], + 'expected' => [ + '_Root_' => [ + 'installed_version' => '', + 'available_version' => 'ITOP_VERSION_FULL', + 'name_code' => 'ITOP_APPLICATION', + ], + ], + ], + 'dummy 2nd installation' => [ + 'aAvailableModules' => [], + 'aInstalledModules' => json_decode(file_get_contents(__DIR__.'/ressources/priv_modules2.json'), true), + 'expected' => [ + '_Root_' => [ + 'installed_version' => '3.3.0-dev-svn', + 'available_version' => 'ITOP_VERSION_FULL', + 'name_code' => 'ITOP_APPLICATION', + ], + ], + ], + 'real_case' => [ + 'aAvailableModules' => $aAvailableModules, + 'aInstalledModules' => json_decode(file_get_contents(__DIR__.'/ressources/priv_modules2.json'), true), + 'expected' => $aAnalyzeInstallationOutput, + ], + ]; + } + + /** + * @dataProvider AnalyzeInstallationProvider + */ + public function testAnalyzeInstallation($aAvailableModules, $aInstalledModules, $expected) + { + $sContent = str_replace(['ITOP_VERSION_FULL', 'ITOP_APPLICATION'], [ITOP_VERSION_FULL, ITOP_APPLICATION], json_encode($expected)); + $expected = json_decode($sContent, true); + + $this->SetNonPublicProperty(AnalyzeInstallation::GetInstance(), "aAvailableModules", $aAvailableModules); + //$aModules = json_decode(file_get_contents(__DIR__.'/ressources/priv_modules2.json'), true); + $this->SetNonPublicProperty(ModuleInstallationRepository::GetInstance(), "aSelectInstall", $aInstalledModules); + + $oConfig = $this->createMock(\Config::class); + + $modulesPath = [ + APPROOT.'extensions', + ]; + $aModules = AnalyzeInstallation::GetInstance()->AnalyzeInstallation($oConfig, $modulesPath, false, null); + $this->assertEquals($expected, $aModules); + } +} diff --git a/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/InstallationChoicesToModuleConverterTest.php b/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/InstallationChoicesToModuleConverterTest.php new file mode 100644 index 0000000000..4aaaacc416 --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/InstallationChoicesToModuleConverterTest.php @@ -0,0 +1,532 @@ +RequireOnceItopFile('/setup/moduleinstallation/InstallationChoicesToModuleConverter.php'); + } + + protected function tearDown(): void + { + parent::tearDown(); + ModuleDiscovery::ResetCache(); + } + + //integration test + public function testGetModulesWithXmlInstallationFile_UsualCustomerPackagesWithNonITIL() + { + $aSearchDirs = $this->GivenModuleDiscoveryInit(); + + $aInstalledModules = InstallationChoicesToModuleConverter::GetInstance()->GetModules( + $this->GivenNonItilChoices(), + $aSearchDirs, + __DIR__.'/ressources/installation.xml' + ); + + $aExpected = [ + 'authent-cas/3.3.0', + 'authent-external/3.3.0', + 'authent-ldap/3.3.0', + 'authent-local/3.3.0', + 'combodo-backoffice-darkmoon-theme/3.3.0', + 'combodo-backoffice-fullmoon-high-contrast-theme/3.3.0', + 'combodo-backoffice-fullmoon-protanopia-deuteranopia-theme/3.3.0', + 'combodo-backoffice-fullmoon-tritanopia-theme/3.3.0', + 'itop-attachments/3.3.0', + 'itop-backup/3.3.0', + 'itop-config/3.3.0', + 'itop-files-information/3.3.0', + 'itop-portal-base/3.3.0', + 'itop-portal/3.3.0', + 'itop-profiles-itil/3.3.0', + 'itop-sla-computation/3.3.0', + 'itop-structure/3.3.0', + 'itop-themes-compat/3.3.0', + 'itop-tickets/3.3.0', + 'itop-welcome-itil/3.3.0', + 'combodo-db-tools/3.3.0', + 'itop-config-mgmt/3.3.0', + 'itop-core-update/3.3.0', + 'itop-datacenter-mgmt/3.3.0', + 'itop-endusers-devices/3.3.0', + 'itop-faq-light/3.3.0', + 'itop-hub-connector/3.3.0', + 'itop-knownerror-mgmt/3.3.0', + 'itop-oauth-client/3.3.0', + 'itop-request-mgmt/3.3.0', + 'itop-service-mgmt/3.3.0', + 'itop-storage-mgmt/3.3.0', + 'itop-virtualization-mgmt/3.3.0', + 'itop-bridge-cmdb-services/3.3.0', + 'itop-bridge-cmdb-ticket/3.3.0', + 'itop-bridge-datacenter-mgmt-services/3.3.0', + 'itop-bridge-endusers-devices-services/3.3.0', + 'itop-bridge-storage-mgmt-services/3.3.0', + 'itop-bridge-virtualization-mgmt-services/3.3.0', + 'itop-bridge-virtualization-storage/3.3.0', + 'itop-change-mgmt/3.3.0', + ]; + $this->assertEquals($aExpected, $aInstalledModules); + } + + //integration test + public function testGetModulesWithXmlInstallationFile_UsualCustomerPackagesWithITIL() + { + $aSearchDirs = $this->GivenModuleDiscoveryInit(); + + $aInstalledModules = InstallationChoicesToModuleConverter::GetInstance()->GetModules( + $this->GivenItilChoices(), + $aSearchDirs, + __DIR__.'/ressources/installation.xml' + ); + + $aExpected = [ + 'authent-cas/3.3.0', + 'authent-external/3.3.0', + 'authent-ldap/3.3.0', + 'authent-local/3.3.0', + 'combodo-backoffice-darkmoon-theme/3.3.0', + 'combodo-backoffice-fullmoon-high-contrast-theme/3.3.0', + 'combodo-backoffice-fullmoon-protanopia-deuteranopia-theme/3.3.0', + 'combodo-backoffice-fullmoon-tritanopia-theme/3.3.0', + 'itop-attachments/3.3.0', + 'itop-backup/3.3.0', + 'itop-config/3.3.0', + 'itop-files-information/3.3.0', + 'itop-portal-base/3.3.0', + 'itop-portal/3.3.0', + 'itop-profiles-itil/3.3.0', + 'itop-sla-computation/3.3.0', + 'itop-structure/3.3.0', + 'itop-themes-compat/3.3.0', + 'itop-tickets/3.3.0', + 'itop-welcome-itil/3.3.0', + 'combodo-db-tools/3.3.0', + 'itop-config-mgmt/3.3.0', + 'itop-core-update/3.3.0', + 'itop-datacenter-mgmt/3.3.0', + 'itop-endusers-devices/3.3.0', + 'itop-hub-connector/3.3.0', + 'itop-incident-mgmt-itil/3.3.0', + 'itop-oauth-client/3.3.0', + 'itop-request-mgmt-itil/3.3.0', + 'itop-service-mgmt/3.3.0', + 'itop-storage-mgmt/3.3.0', + 'itop-virtualization-mgmt/3.3.0', + 'itop-bridge-cmdb-services/3.3.0', + 'itop-bridge-cmdb-ticket/3.3.0', + 'itop-bridge-datacenter-mgmt-services/3.3.0', + 'itop-bridge-endusers-devices-services/3.3.0', + 'itop-bridge-storage-mgmt-services/3.3.0', + 'itop-bridge-virtualization-mgmt-services/3.3.0', + 'itop-bridge-virtualization-storage/3.3.0', + 'itop-change-mgmt-itil/3.3.0', + 'itop-full-itil/3.3.0', + ]; + $this->assertEquals($aExpected, $aInstalledModules); + } + + //integration test + public function testGetModulesWithXmlInstallationFile_LegacyPackages() + { + $aSearchDirs = $this->GivenModuleDiscoveryInit(); + + //no choices means all default ones... + $aNoInstallationChoices = []; + + $aInstalledModules = InstallationChoicesToModuleConverter::GetInstance()->GetModules( + $aNoInstallationChoices, + $aSearchDirs + ); + + $aExpected = [ + 'authent-cas/3.3.0', + 'authent-external/3.3.0', + 'authent-ldap/3.3.0', + 'authent-local/3.3.0', + 'combodo-backoffice-darkmoon-theme/3.3.0', + 'combodo-backoffice-fullmoon-high-contrast-theme/3.3.0', + 'combodo-backoffice-fullmoon-protanopia-deuteranopia-theme/3.3.0', + 'combodo-backoffice-fullmoon-tritanopia-theme/3.3.0', + 'itop-backup/3.3.0', + 'itop-config/3.3.0', + 'itop-files-information/3.3.0', + 'itop-portal-base/3.3.0', + 'itop-profiles-itil/3.3.0', + 'itop-sla-computation/3.3.0', + 'itop-structure/3.3.0', + 'itop-welcome-itil/3.3.0', + ]; + $this->assertEquals($aExpected, $aInstalledModules); + } + + private function GivenNewExtensionDir($MainDir, $sExtensionCode, $sModuleCode, $sModuleVersion): string + { + $sExtDir = "$MainDir/$sExtensionCode"; + + mkdir($sExtDir, recursive:true); + $sModuleDir = $sExtDir."/$sModuleCode"; + mkdir($sModuleDir); + $sContent = << '$sModuleCode', + 'category' => 'authentication', + 'dependencies' => [], + 'mandatory' => true, + 'visible' => true, + 'datamodel' => [], + 'webservice' => [], + 'data.struct' => [], + 'data.sample' => [], + 'doc.manual_setup' => '', + 'doc.more_information' => '', + ] +); +PHP; + file_put_contents($sModuleDir."/module.$sModuleCode.php", $sContent); + + return $sExtDir; + } + + //integration + public function testGetModules_ComputeAdditionalExtensionDirectories() + { + $aSearchDirs = $this->GivenModuleDiscoveryInit(); + + $MainDir = __DIR__."/ressources/InstallationChoicesToModuleConverterTest"; + $this->aFileToClean [] = $MainDir; + $aExtensionDirs = [ + //should replace same one in the package + $this->GivenNewExtensionDir($MainDir, 'itop-oauth-client', 'itop-oauth-client', '6.6.0'), + //not in the package => should be added after installation + $this->GivenNewExtensionDir($MainDir, 'shadok', 'gabu-zomeu', '1.2.3'), + //same one in the package should remain + $this->GivenNewExtensionDir($MainDir, 'itop-files-information', 'itop-files-information', '3.3.0'), + ]; + + $aInstalledModules = InstallationChoicesToModuleConverter::GetInstance()->GetModules( + $this->GivenNonItilChoices(), + $aSearchDirs, + __DIR__.'/ressources/installation.xml', + $aExtensionDirs, + ); + + $aExpected = [ + 'authent-cas/3.3.0', + 'authent-external/3.3.0', + 'authent-ldap/3.3.0', + 'authent-local/3.3.0', + 'combodo-backoffice-darkmoon-theme/3.3.0', + 'combodo-backoffice-fullmoon-high-contrast-theme/3.3.0', + 'combodo-backoffice-fullmoon-protanopia-deuteranopia-theme/3.3.0', + 'combodo-backoffice-fullmoon-tritanopia-theme/3.3.0', + 'itop-attachments/3.3.0', + 'itop-backup/3.3.0', + 'itop-config/3.3.0', + 'itop-files-information/3.3.0', + 'itop-portal-base/3.3.0', + 'itop-portal/3.3.0', + 'itop-profiles-itil/3.3.0', + 'itop-sla-computation/3.3.0', + 'itop-structure/3.3.0', + 'itop-themes-compat/3.3.0', + 'itop-tickets/3.3.0', + 'itop-welcome-itil/3.3.0', + 'combodo-db-tools/3.3.0', + 'itop-config-mgmt/3.3.0', + 'itop-core-update/3.3.0', + 'itop-datacenter-mgmt/3.3.0', + 'itop-endusers-devices/3.3.0', + 'itop-faq-light/3.3.0', + 'itop-hub-connector/3.3.0', + 'itop-knownerror-mgmt/3.3.0', + 'itop-oauth-client/6.6.0', + 'itop-request-mgmt/3.3.0', + 'itop-service-mgmt/3.3.0', + 'itop-storage-mgmt/3.3.0', + 'itop-virtualization-mgmt/3.3.0', + 'itop-bridge-cmdb-services/3.3.0', + 'itop-bridge-cmdb-ticket/3.3.0', + 'itop-bridge-datacenter-mgmt-services/3.3.0', + 'itop-bridge-endusers-devices-services/3.3.0', + 'itop-bridge-storage-mgmt-services/3.3.0', + 'itop-bridge-virtualization-mgmt-services/3.3.0', + 'itop-bridge-virtualization-storage/3.3.0', + 'itop-change-mgmt/3.3.0', + 'gabu-zomeu/1.2.3', + ]; + $this->assertEquals($aExpected, $aInstalledModules); + } + + public function testIsDefaultModule_RootModuleShouldNeverBeDefault() + { + $sModuleId = ROOT_MODULE; + $aModuleInfo = ['category' => 'authentication', 'visible' => false]; + $this->assertFalse($this->CallIsDefault($sModuleId, $aModuleInfo)); + } + + public function testIsDefaultModule_AutoselectShouldNeverBeDefault() + { + $sModuleId = 'autoselect_module'; + $aModuleInfo = ['category' => 'authentication', 'visible' => false, 'auto_select' => true]; + $this->assertFalse($this->CallIsDefault($sModuleId, $aModuleInfo)); + } + + public function testIsDefaultModule_AuthenticationModuleShouldBeDefault() + { + $sModuleId = 'authentication_module'; + $aModuleInfo = ['category' => 'authentication', 'visible' => true]; + $this->assertTrue($this->CallIsDefault($sModuleId, $aModuleInfo)); + } + + public function testIsDefaultModule_HiddenModuleShouldBeDefault() + { + $sModuleId = 'hidden_module'; + $aModuleInfo = ['category' => 'business', 'visible' => false]; + $this->assertTrue($this->CallIsDefault($sModuleId, $aModuleInfo)); + } + + public function testIsDefaultModule_NonModuleDefaultCase() + { + $sModuleId = 'any_module'; + $aModuleInfo = ['category' => 'business', 'visible' => true]; + $this->assertFalse($this->CallIsDefault($sModuleId, $aModuleInfo)); + } + + private function CallIsDefault($sModuleId, $aModuleInfo): bool + { + return $this->InvokeNonPublicMethod(InstallationChoicesToModuleConverter::class, 'IsDefaultModule', InstallationChoicesToModuleConverter::GetInstance(), [$sModuleId, $aModuleInfo]); + } + + public function testIsAutoSelectedModule_RootModuleShouldNeverBeAutoSelect() + { + $sModuleId = ROOT_MODULE; + $aModuleInfo = ['auto_select' => true]; + $this->assertFalse($this->CallIsAutoSelectedModule([], $sModuleId, $aModuleInfo)); + } + + public function testIsAutoSelectedModule_NoAutoselectByDefault() + { + $sModuleId = 'autoselect_module'; + $aModuleInfo = []; + $this->assertFalse($this->CallIsAutoSelectedModule([], $sModuleId, $aModuleInfo)); + } + + /** + * @return void + * cf DependencyExpression dedicated tests + */ + public function testIsAutoSelectedModule_UseInstalledModulesForComputation() + { + $sModuleId = "any_module"; + $aModuleInfo = ['auto_select' => 'SetupInfo::ModuleIsSelected("a") && SetupInfo::ModuleIsSelected("b")']; + $aInstalledModules = ['a' => true, 'b' => true]; + $this->assertTrue($this->CallIsAutoSelectedModule($aInstalledModules, $sModuleId, $aModuleInfo)); + } + + private function CallIsAutoSelectedModule($aInstalledModules, $sModuleId, $aModuleInfo): bool + { + return $this->InvokeNonPublicMethod(InstallationChoicesToModuleConverter::class, 'IsAutoSelectedModule', InstallationChoicesToModuleConverter::GetInstance(), [$aInstalledModules, $sModuleId, $aModuleInfo]); + } + + public function testProcessInstallationChoices_Default() + { + $aRes = []; + $aInstallationDescription = $this->GivenInstallationChoiceDescription(); + + $this->CallGetModuleNamesFromInstallationChoices([], $aInstallationDescription, $aRes); + + $aExpected = [ + 'combodo-backoffice-darkmoon-theme' => true, + 'combodo-backoffice-fullmoon-high-contrast-theme' => true, + 'combodo-backoffice-fullmoon-protanopia-deuteranopia-theme' => true, + 'combodo-backoffice-fullmoon-tritanopia-theme' => true, + 'itop-attachments' => true, + 'itop-backup' => true, + 'itop-config' => true, + 'itop-files-information' => true, + 'itop-profiles-itil' => true, + 'itop-structure' => true, + 'itop-themes-compat' => true, + 'itop-tickets' => true, + 'itop-welcome-itil' => true, + 'combodo-db-tools' => true, + 'itop-config-mgmt' => true, + 'itop-core-update' => true, + 'itop-hub-connector' => true, + 'itop-oauth-client' => true, + 'combodo-password-expiration' => true, + 'combodo-webhook-integration' => true, + 'combodo-my-account-user-info' => true, + 'authent-token' => true, + ]; + $this->assertEquals($aExpected, $aRes); + } + + public function testProcessInstallationChoices_NonItilChoices() + { + $aRes = []; + $aInstallationDescription = $this->GivenInstallationChoiceDescription(); + + $this->CallGetModuleNamesFromInstallationChoices($this->GivenNonItilChoices(), $aInstallationDescription, $aRes); + + $aExpected = [ + 'combodo-backoffice-darkmoon-theme' => true, + 'combodo-backoffice-fullmoon-high-contrast-theme' => true, + 'combodo-backoffice-fullmoon-protanopia-deuteranopia-theme' => true, + 'combodo-backoffice-fullmoon-tritanopia-theme' => true, + 'itop-attachments' => true, + 'itop-backup' => true, + 'itop-config' => true, + 'itop-files-information' => true, + 'itop-profiles-itil' => true, + 'itop-structure' => true, + 'itop-themes-compat' => true, + 'itop-tickets' => true, + 'itop-welcome-itil' => true, + 'combodo-db-tools' => true, + 'itop-config-mgmt' => true, + 'itop-core-update' => true, + 'itop-hub-connector' => true, + 'itop-oauth-client' => true, + 'combodo-password-expiration' => true, + 'combodo-webhook-integration' => true, + 'combodo-my-account-user-info' => true, + 'authent-token' => true, + 'itop-datacenter-mgmt' => true, + 'itop-endusers-devices' => true, + 'itop-storage-mgmt' => true, + 'itop-virtualization-mgmt' => true, + 'itop-service-mgmt' => true, + 'itop-request-mgmt' => true, + 'itop-portal' => true, + 'itop-portal-base' => true, + 'itop-change-mgmt' => true, + 'itop-faq-light' => true, + 'itop-knownerror-mgmt' => true, + ]; + $this->assertEquals($aExpected, $aRes); + } + + public function testProcessInstallationChoices_ItilChoices() + { + $aRes = []; + $aInstallationDescription = $this->GivenInstallationChoiceDescription(); + + $this->CallGetModuleNamesFromInstallationChoices($this->GivenItilChoices(), $aInstallationDescription, $aRes); + + $aExpected = [ + 'combodo-backoffice-darkmoon-theme' => true, + 'combodo-backoffice-fullmoon-high-contrast-theme' => true, + 'combodo-backoffice-fullmoon-protanopia-deuteranopia-theme' => true, + 'combodo-backoffice-fullmoon-tritanopia-theme' => true, + 'itop-attachments' => true, + 'itop-backup' => true, + 'itop-config' => true, + 'itop-files-information' => true, + 'itop-profiles-itil' => true, + 'itop-structure' => true, + 'itop-themes-compat' => true, + 'itop-tickets' => true, + 'itop-welcome-itil' => true, + 'combodo-db-tools' => true, + 'itop-config-mgmt' => true, + 'itop-core-update' => true, + 'itop-hub-connector' => true, + 'itop-oauth-client' => true, + 'combodo-password-expiration' => true, + 'combodo-webhook-integration' => true, + 'combodo-my-account-user-info' => true, + 'authent-token' => true, + 'itop-datacenter-mgmt' => true, + 'itop-endusers-devices' => true, + 'itop-storage-mgmt' => true, + 'itop-virtualization-mgmt' => true, + 'itop-service-mgmt' => true, + 'itop-portal' => true, + 'itop-portal-base' => true, + 'itop-request-mgmt-itil' => true, + 'itop-incident-mgmt-itil' => true, + 'itop-change-mgmt-itil' => true, + ]; + $this->assertEquals($aExpected, $aRes); + } + + private function CallGetModuleNamesFromInstallationChoices(array $aInstallationChoices, array $aInstallationDescription, array &$aModuleNames) + { + $this->InvokeNonPublicMethod( + InstallationChoicesToModuleConverter::class, + 'GetModuleNamesFromInstallationChoices', + InstallationChoicesToModuleConverter::GetInstance(), + [$aInstallationChoices, $aInstallationDescription, &$aModuleNames] + ); + } + + private function GivenInstallationChoiceDescription(): array + { + $oXMLParameters = new XMLParameters(__DIR__."/ressources/installation.xml"); + return $oXMLParameters->Get('steps', []); + } + + private function GivenAllModules(): array + { + return json_decode(file_get_contents(__DIR__.'/ressources/available_modules.json'), true); + } + + private function GivenNonItilChoices(): array + { + return [ + 'itop-config-mgmt-core', + 'itop-config-mgmt-datacenter', + 'itop-config-mgmt-end-user', + 'itop-config-mgmt-storage', + 'itop-config-mgmt-virtualization', + 'itop-service-mgmt-enterprise', + 'itop-ticket-mgmt-simple-ticket', + 'itop-ticket-mgmt-simple-ticket-enhanced-portal', + 'itop-change-mgmt-simple', + 'itop-kown-error-mgmt', + ]; + } + + private function GivenItilChoices(): array + { + return [ + 'itop-config-mgmt-datacenter', + 'itop-config-mgmt-end-user', + 'itop-config-mgmt-storage', + 'itop-config-mgmt-virtualization', + 'itop-service-mgmt-enterprise', + 'itop-ticket-mgmt-itil', + 'itop-ticket-mgmt-itil-user-request', + 'itop-ticket-mgmt-itil-incident', + 'itop-ticket-mgmt-itil-enhanced-portal', + 'itop-change-mgmt-itil', + 'itop-config-mgmt-core', + + ]; + } + + private function GivenModuleDiscoveryInit(): array + { + $aSearchDirs = [APPROOT.'datamodels/2.x']; + $this->SetNonPublicStaticProperty(ModuleDiscovery::class, 'm_aSearchDirs', $aSearchDirs); + $this->SetNonPublicStaticProperty(ModuleDiscovery::class, 'm_aModules', $this->GivenAllModules()); + return $aSearchDirs; + } +} diff --git a/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/analyze_installation_output.json b/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/analyze_installation_output.json new file mode 100644 index 0000000000..f24517fed7 --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/analyze_installation_output.json @@ -0,0 +1,2265 @@ +{ + "_Root_": { + "installed_version": "3.3.0-dev-svn", + "available_version": "ITOP_VERSION_FULL", + "name_code": "ITOP_APPLICATION" + }, + "authent-cas": { + "label": "CAS SSO", + "category": "authentication", + "dependencies": [], + "mandatory": true, + "visible": true, + "datamodel": [ + "vendor\/autoload.php", + "src\/CASLoginExtension.php" + ], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": { + "cas_debug": false, + "cas_host": "", + "cas_port": "", + "cas_context": "", + "cas_version": "", + "service_base_url": "" + }, + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/authent-cas\/module.authent-cas.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/authent-cas", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/authent-cas\/module.authent-cas.php", + "dictionary": [ + "2.x\/authent-cas\/dictionaries\/de.dict.authent-cas.php", + "2.x\/authent-cas\/dictionaries\/en_gb.dict.authent-cas.php", + "2.x\/authent-cas\/dictionaries\/cs.dict.authent-cas.php", + "2.x\/authent-cas\/dictionaries\/pl.dict.authent-cas.php", + "2.x\/authent-cas\/dictionaries\/nl.dict.authent-cas.php", + "2.x\/authent-cas\/dictionaries\/da.dict.authent-cas.php", + "2.x\/authent-cas\/dictionaries\/tr.dict.authent-cas.php", + "2.x\/authent-cas\/dictionaries\/ru.dict.authent-cas.php", + "2.x\/authent-cas\/dictionaries\/ja.dict.authent-cas.php", + "2.x\/authent-cas\/dictionaries\/es_cr.dict.authent-cas.php", + "2.x\/authent-cas\/dictionaries\/it.dict.authent-cas.php", + "2.x\/authent-cas\/dictionaries\/pt_br.dict.authent-cas.php", + "2.x\/authent-cas\/dictionaries\/sk.dict.authent-cas.php", + "2.x\/authent-cas\/dictionaries\/hu.dict.authent-cas.php", + "2.x\/authent-cas\/dictionaries\/zh_cn.dict.authent-cas.php", + "2.x\/authent-cas\/dictionaries\/en.dict.authent-cas.php", + "2.x\/authent-cas\/dictionaries\/fr.dict.authent-cas.php" + ], + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 2, + "message": "the module is part of the application" + }, + "uninstall": { + "flag": 3, + "message": "the module is part of the application" + } + }, + "authent-external": { + "label": "External user authentication", + "category": "authentication", + "dependencies": [], + "mandatory": false, + "visible": true, + "datamodel": [ + "model.authent-external.php" + ], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/authent-external\/module.authent-external.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/authent-external", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/authent-external\/module.authent-external.php", + "dictionary": [ + "2.x\/authent-external\/dictionaries\/fr.dict.authent-external.php", + "2.x\/authent-external\/dictionaries\/de.dict.authent-external.php", + "2.x\/authent-external\/dictionaries\/zh_cn.dict.authent-external.php", + "2.x\/authent-external\/dictionaries\/pl.dict.authent-external.php", + "2.x\/authent-external\/dictionaries\/tr.dict.authent-external.php", + "2.x\/authent-external\/dictionaries\/en_gb.dict.authent-external.php", + "2.x\/authent-external\/dictionaries\/pt_br.dict.authent-external.php", + "2.x\/authent-external\/dictionaries\/da.dict.authent-external.php", + "2.x\/authent-external\/dictionaries\/ru.dict.authent-external.php", + "2.x\/authent-external\/dictionaries\/cs.dict.authent-external.php", + "2.x\/authent-external\/dictionaries\/it.dict.authent-external.php", + "2.x\/authent-external\/dictionaries\/en.dict.authent-external.php", + "2.x\/authent-external\/dictionaries\/hu.dict.authent-external.php", + "2.x\/authent-external\/dictionaries\/sk.dict.authent-external.php", + "2.x\/authent-external\/dictionaries\/ja.dict.authent-external.php", + "2.x\/authent-external\/dictionaries\/nl.dict.authent-external.php", + "2.x\/authent-external\/dictionaries\/es_cr.dict.authent-external.php" + ], + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 1, + "message": "" + }, + "uninstall": { + "flag": 1, + "message": "" + } + }, + "authent-ldap": { + "label": "User authentication based on LDAP", + "category": "authentication", + "dependencies": [], + "mandatory": false, + "visible": true, + "installer": "AuthentLDAPInstaller", + "datamodel": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": { + "uri": "ldap:\/\/localhost", + "default_user": "", + "default_pwd": "", + "base_dn": "dc=yourcompany,dc=com", + "user_query": "(&(uid=%1$s)(inetuserstatus=ACTIVE))", + "options": { + "17": 3, + "8": 0 + }, + "start_tls": false, + "debug": false, + "servers": [] + }, + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/authent-ldap\/module.authent-ldap.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/authent-ldap", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/authent-ldap\/module.authent-ldap.php", + "dictionary": [ + "2.x\/authent-ldap\/dictionaries\/en.dict.authent-ldap.php", + "2.x\/authent-ldap\/dictionaries\/pl.dict.authent-ldap.php", + "2.x\/authent-ldap\/dictionaries\/ru.dict.authent-ldap.php", + "2.x\/authent-ldap\/dictionaries\/cs.dict.authent-ldap.php", + "2.x\/authent-ldap\/dictionaries\/es_cr.dict.authent-ldap.php", + "2.x\/authent-ldap\/dictionaries\/zh_cn.dict.authent-ldap.php", + "2.x\/authent-ldap\/dictionaries\/pt_br.dict.authent-ldap.php", + "2.x\/authent-ldap\/dictionaries\/it.dict.authent-ldap.php", + "2.x\/authent-ldap\/dictionaries\/tr.dict.authent-ldap.php", + "2.x\/authent-ldap\/dictionaries\/fr.dict.authent-ldap.php", + "2.x\/authent-ldap\/dictionaries\/en_gb.dict.authent-ldap.php", + "2.x\/authent-ldap\/dictionaries\/de.dict.authent-ldap.php", + "2.x\/authent-ldap\/dictionaries\/da.dict.authent-ldap.php", + "2.x\/authent-ldap\/dictionaries\/nl.dict.authent-ldap.php", + "2.x\/authent-ldap\/dictionaries\/hu.dict.authent-ldap.php", + "2.x\/authent-ldap\/dictionaries\/sk.dict.authent-ldap.php", + "2.x\/authent-ldap\/dictionaries\/ja.dict.authent-ldap.php" + ], + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 1, + "message": "" + }, + "uninstall": { + "flag": 1, + "message": "" + } + }, + "authent-local": { + "label": "User authentication based on the local DB", + "category": "authentication", + "dependencies": [], + "mandatory": true, + "visible": true, + "datamodel": [ + "model.authent-local.php" + ], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/authent-local\/module.authent-local.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/authent-local", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/authent-local\/module.authent-local.php", + "dictionary": [ + "2.x\/authent-local\/dictionaries\/en_gb.dict.authent-local.php", + "2.x\/authent-local\/dictionaries\/hu.dict.authent-local.php", + "2.x\/authent-local\/dictionaries\/de.dict.authent-local.php", + "2.x\/authent-local\/dictionaries\/ja.dict.authent-local.php", + "2.x\/authent-local\/dictionaries\/fr.dict.authent-local.php", + "2.x\/authent-local\/dictionaries\/es_cr.dict.authent-local.php", + "2.x\/authent-local\/dictionaries\/it.dict.authent-local.php", + "2.x\/authent-local\/dictionaries\/tr.dict.authent-local.php", + "2.x\/authent-local\/dictionaries\/da.dict.authent-local.php", + "2.x\/authent-local\/dictionaries\/sk.dict.authent-local.php", + "2.x\/authent-local\/dictionaries\/pl.dict.authent-local.php", + "2.x\/authent-local\/dictionaries\/ru.dict.authent-local.php", + "2.x\/authent-local\/dictionaries\/nl.dict.authent-local.php", + "2.x\/authent-local\/dictionaries\/zh_cn.dict.authent-local.php", + "2.x\/authent-local\/dictionaries\/cs.dict.authent-local.php", + "2.x\/authent-local\/dictionaries\/en.dict.authent-local.php", + "2.x\/authent-local\/dictionaries\/pt_br.dict.authent-local.php" + ], + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 2, + "message": "the module is part of the application" + }, + "uninstall": { + "flag": 3, + "message": "the module is part of the application" + } + }, + "combodo-backoffice-darkmoon-theme": { + "label": "Backoffice: Darkmoon theme", + "category": "business", + "dependencies": [], + "mandatory": true, + "visible": false, + "datamodel": [], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/combodo-backoffice-darkmoon-theme\/module.combodo-backoffice-darkmoon-theme.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/combodo-backoffice-darkmoon-theme", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/combodo-backoffice-darkmoon-theme\/module.combodo-backoffice-darkmoon-theme.php", + "dictionary": [ + "2.x\/combodo-backoffice-darkmoon-theme\/dictionaries\/es_cr.dict.combodo-backoffice-darkmoon-theme.php", + "2.x\/combodo-backoffice-darkmoon-theme\/dictionaries\/tr.dict.combodo-backoffice-darkmoon-theme.php", + "2.x\/combodo-backoffice-darkmoon-theme\/dictionaries\/sk.dict.combodo-backoffice-darkmoon-theme.php", + "2.x\/combodo-backoffice-darkmoon-theme\/dictionaries\/pt_br.dict.combodo-backoffice-darkmoon-theme.php", + "2.x\/combodo-backoffice-darkmoon-theme\/dictionaries\/it.dict.combodo-backoffice-darkmoon-theme.php", + "2.x\/combodo-backoffice-darkmoon-theme\/dictionaries\/en_gb.dict.combodo-backoffice-darkmoon-theme.php", + "2.x\/combodo-backoffice-darkmoon-theme\/dictionaries\/da.dict.combodo-backoffice-darkmoon-theme.php", + "2.x\/combodo-backoffice-darkmoon-theme\/dictionaries\/nl.dict.combodo-backoffice-darkmoon-theme.php", + "2.x\/combodo-backoffice-darkmoon-theme\/dictionaries\/ja.dict.combodo-backoffice-darkmoon-theme.php", + "2.x\/combodo-backoffice-darkmoon-theme\/dictionaries\/hu.dict.combodo-backoffice-darkmoon-theme.php", + "2.x\/combodo-backoffice-darkmoon-theme\/dictionaries\/pl.dict.combodo-backoffice-darkmoon-theme.php", + "2.x\/combodo-backoffice-darkmoon-theme\/dictionaries\/de.dict.combodo-backoffice-darkmoon-theme.php", + "2.x\/combodo-backoffice-darkmoon-theme\/dictionaries\/zh_cn.dict.combodo-backoffice-darkmoon-theme.php", + "2.x\/combodo-backoffice-darkmoon-theme\/dictionaries\/ru.dict.combodo-backoffice-darkmoon-theme.php", + "2.x\/combodo-backoffice-darkmoon-theme\/dictionaries\/fr.dict.combodo-backoffice-darkmoon-theme.php", + "2.x\/combodo-backoffice-darkmoon-theme\/dictionaries\/en.dict.combodo-backoffice-darkmoon-theme.php", + "2.x\/combodo-backoffice-darkmoon-theme\/dictionaries\/cs.dict.combodo-backoffice-darkmoon-theme.php" + ], + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 2, + "message": "the module is part of the application" + }, + "uninstall": { + "flag": 3, + "message": "the module is part of the application" + } + }, + "combodo-backoffice-fullmoon-high-contrast-theme": { + "label": "Backoffice: Fullmoon with high contrast accessibility theme", + "category": "business", + "dependencies": [], + "mandatory": true, + "visible": false, + "datamodel": [], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/combodo-backoffice-fullmoon-high-contrast-theme\/module.combodo-backoffice-fullmoon-high-contrast-theme.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/combodo-backoffice-fullmoon-high-contrast-theme", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/combodo-backoffice-fullmoon-high-contrast-theme\/module.combodo-backoffice-fullmoon-high-contrast-theme.php", + "dictionary": [ + "2.x\/combodo-backoffice-fullmoon-high-contrast-theme\/dictionaries\/es_cr.dict.combodo-backoffice-fullmoon-high-contrast-theme.php", + "2.x\/combodo-backoffice-fullmoon-high-contrast-theme\/dictionaries\/en_gb.dict.combodo-backoffice-fullmoon-high-contrast-theme.php", + "2.x\/combodo-backoffice-fullmoon-high-contrast-theme\/dictionaries\/sk.dict.combodo-backoffice-fullmoon-high-contrast-theme.php", + "2.x\/combodo-backoffice-fullmoon-high-contrast-theme\/dictionaries\/tr.dict.combodo-backoffice-fullmoon-high-contrast-theme.php", + "2.x\/combodo-backoffice-fullmoon-high-contrast-theme\/dictionaries\/en.dict.combodo-backoffice-fullmoon-high-contrast-theme.php", + "2.x\/combodo-backoffice-fullmoon-high-contrast-theme\/dictionaries\/pt_br.dict.combodo-backoffice-fullmoon-high-contrast-theme.php", + "2.x\/combodo-backoffice-fullmoon-high-contrast-theme\/dictionaries\/cs.dict.combodo-backoffice-fullmoon-high-contrast-theme.php", + "2.x\/combodo-backoffice-fullmoon-high-contrast-theme\/dictionaries\/fr.dict.combodo-backoffice-fullmoon-high-contrast-theme.php", + "2.x\/combodo-backoffice-fullmoon-high-contrast-theme\/dictionaries\/hu.dict.combodo-backoffice-fullmoon-high-contrast-theme.php", + "2.x\/combodo-backoffice-fullmoon-high-contrast-theme\/dictionaries\/it.dict.combodo-backoffice-fullmoon-high-contrast-theme.php", + "2.x\/combodo-backoffice-fullmoon-high-contrast-theme\/dictionaries\/ru.dict.combodo-backoffice-fullmoon-high-contrast-theme.php", + "2.x\/combodo-backoffice-fullmoon-high-contrast-theme\/dictionaries\/pl.dict.combodo-backoffice-fullmoon-high-contrast-theme.php", + "2.x\/combodo-backoffice-fullmoon-high-contrast-theme\/dictionaries\/da.dict.combodo-backoffice-fullmoon-high-contrast-theme.php", + "2.x\/combodo-backoffice-fullmoon-high-contrast-theme\/dictionaries\/ja.dict.combodo-backoffice-fullmoon-high-contrast-theme.php", + "2.x\/combodo-backoffice-fullmoon-high-contrast-theme\/dictionaries\/zh_cn.dict.combodo-backoffice-fullmoon-high-contrast-theme.php", + "2.x\/combodo-backoffice-fullmoon-high-contrast-theme\/dictionaries\/nl.dict.combodo-backoffice-fullmoon-high-contrast-theme.php", + "2.x\/combodo-backoffice-fullmoon-high-contrast-theme\/dictionaries\/de.dict.combodo-backoffice-fullmoon-high-contrast-theme.php" + ], + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 2, + "message": "the module is part of the application" + }, + "uninstall": { + "flag": 3, + "message": "the module is part of the application" + } + }, + "combodo-backoffice-fullmoon-protanopia-deuteranopia-theme": { + "label": "Backoffice: Fullmoon with protonopia & deuteranopia accessibility theme", + "category": "business", + "dependencies": [], + "mandatory": true, + "visible": false, + "datamodel": [], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/module.combodo-backoffice-fullmoon-protanopia-deuteranopia-theme.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/module.combodo-backoffice-fullmoon-protanopia-deuteranopia-theme.php", + "dictionary": [ + "2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/dictionaries\/pl.dict.combodo-backoffice-fullmoon-protanopia-deuteranopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/dictionaries\/ja.dict.combodo-backoffice-fullmoon-protanopia-deuteranopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/dictionaries\/da.dict.combodo-backoffice-fullmoon-protanopia-deuteranopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/dictionaries\/de.dict.combodo-backoffice-fullmoon-protanopia-deuteranopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/dictionaries\/cs.dict.combodo-backoffice-fullmoon-protanopia-deuteranopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/dictionaries\/es_cr.dict.combodo-backoffice-fullmoon-protanopia-deuteranopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/dictionaries\/zh_cn.dict.combodo-backoffice-fullmoon-protanopia-deuteranopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/dictionaries\/sk.dict.combodo-backoffice-fullmoon-protanopia-deuteranopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/dictionaries\/nl.dict.combodo-backoffice-fullmoon-protanopia-deuteranopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/dictionaries\/tr.dict.combodo-backoffice-fullmoon-protanopia-deuteranopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/dictionaries\/pt_br.dict.combodo-backoffice-fullmoon-protanopia-deuteranopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/dictionaries\/it.dict.combodo-backoffice-fullmoon-protanopia-deuteranopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/dictionaries\/fr.dict.combodo-backoffice-fullmoon-protanopia-deuteranopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/dictionaries\/ru.dict.combodo-backoffice-fullmoon-protanopia-deuteranopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/dictionaries\/en_gb.dict.combodo-backoffice-fullmoon-protanopia-deuteranopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/dictionaries\/hu.dict.combodo-backoffice-fullmoon-protanopia-deuteranopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/dictionaries\/en.dict.combodo-backoffice-fullmoon-protanopia-deuteranopia-theme.php" + ], + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 2, + "message": "the module is part of the application" + }, + "uninstall": { + "flag": 3, + "message": "the module is part of the application" + } + }, + "combodo-backoffice-fullmoon-tritanopia-theme": { + "label": "Backoffice: Fullmoon with tritanopia accessibility theme", + "category": "business", + "dependencies": [], + "mandatory": true, + "visible": false, + "datamodel": [], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/combodo-backoffice-fullmoon-tritanopia-theme\/module.combodo-backoffice-fullmoon-tritanopia-theme.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/combodo-backoffice-fullmoon-tritanopia-theme", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/combodo-backoffice-fullmoon-tritanopia-theme\/module.combodo-backoffice-fullmoon-tritanopia-theme.php", + "dictionary": [ + "2.x\/combodo-backoffice-fullmoon-tritanopia-theme\/dictionaries\/en.dict.combodo-backoffice-fullmoon-tritanopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-tritanopia-theme\/dictionaries\/ru.dict.combodo-backoffice-fullmoon-tritanopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-tritanopia-theme\/dictionaries\/da.dict.combodo-backoffice-fullmoon-tritanopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-tritanopia-theme\/dictionaries\/fr.dict.combodo-backoffice-fullmoon-tritanopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-tritanopia-theme\/dictionaries\/pl.dict.combodo-backoffice-fullmoon-tritanopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-tritanopia-theme\/dictionaries\/it.dict.combodo-backoffice-fullmoon-tritanopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-tritanopia-theme\/dictionaries\/ja.dict.combodo-backoffice-fullmoon-tritanopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-tritanopia-theme\/dictionaries\/hu.dict.combodo-backoffice-fullmoon-tritanopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-tritanopia-theme\/dictionaries\/tr.dict.combodo-backoffice-fullmoon-tritanopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-tritanopia-theme\/dictionaries\/en_gb.dict.combodo-backoffice-fullmoon-tritanopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-tritanopia-theme\/dictionaries\/de.dict.combodo-backoffice-fullmoon-tritanopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-tritanopia-theme\/dictionaries\/nl.dict.combodo-backoffice-fullmoon-tritanopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-tritanopia-theme\/dictionaries\/zh_cn.dict.combodo-backoffice-fullmoon-tritanopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-tritanopia-theme\/dictionaries\/sk.dict.combodo-backoffice-fullmoon-tritanopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-tritanopia-theme\/dictionaries\/pt_br.dict.combodo-backoffice-fullmoon-tritanopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-tritanopia-theme\/dictionaries\/cs.dict.combodo-backoffice-fullmoon-tritanopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-tritanopia-theme\/dictionaries\/es_cr.dict.combodo-backoffice-fullmoon-tritanopia-theme.php" + ], + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 2, + "message": "the module is part of the application" + }, + "uninstall": { + "flag": 3, + "message": "the module is part of the application" + } + }, + "itop-attachments": { + "label": "Tickets Attachments", + "category": "business", + "dependencies": [], + "mandatory": false, + "visible": true, + "installer": "AttachmentInstaller", + "datamodel": [ + "vendor\/autoload.php", + "main.itop-attachments.php", + "src\/Trigger\/TriggerOnAttachmentCreate.php", + "src\/Trigger\/TriggerOnAttachmentDelete.php", + "src\/Trigger\/TriggerOnAttachmentDownload.php", + "renderers.itop-attachments.php" + ], + "webservice": [], + "dictionary": [ + "2.x\/itop-attachments\/dictionaries\/cs.dict.itop-attachments.php", + "2.x\/itop-attachments\/dictionaries\/ja.dict.itop-attachments.php", + "2.x\/itop-attachments\/dictionaries\/es_cr.dict.itop-attachments.php", + "2.x\/itop-attachments\/dictionaries\/ru.dict.itop-attachments.php", + "2.x\/itop-attachments\/dictionaries\/it.dict.itop-attachments.php", + "2.x\/itop-attachments\/dictionaries\/zh_cn.dict.itop-attachments.php", + "2.x\/itop-attachments\/dictionaries\/hu.dict.itop-attachments.php", + "2.x\/itop-attachments\/dictionaries\/da.dict.itop-attachments.php", + "2.x\/itop-attachments\/dictionaries\/en.dict.itop-attachments.php", + "2.x\/itop-attachments\/dictionaries\/sk.dict.itop-attachments.php", + "2.x\/itop-attachments\/dictionaries\/pt_br.dict.itop-attachments.php", + "2.x\/itop-attachments\/dictionaries\/fr.dict.itop-attachments.php", + "2.x\/itop-attachments\/dictionaries\/de.dict.itop-attachments.php", + "2.x\/itop-attachments\/dictionaries\/en_gb.dict.itop-attachments.php", + "2.x\/itop-attachments\/dictionaries\/pl.dict.itop-attachments.php", + "2.x\/itop-attachments\/dictionaries\/tr.dict.itop-attachments.php", + "2.x\/itop-attachments\/dictionaries\/nl.dict.itop-attachments.php" + ], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": { + "allowed_classes": [ + "Ticket" + ], + "position": "relations", + "preview_max_width": 290, + "icon_preview_max_size": 500000 + }, + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-attachments\/module.itop-attachments.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-attachments", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-attachments\/module.itop-attachments.php", + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 1, + "message": "" + }, + "uninstall": { + "flag": 1, + "message": "" + } + }, + "itop-backup": { + "label": "Backup utilities", + "category": "Application management", + "dependencies": [], + "mandatory": true, + "visible": false, + "datamodel": [ + "main.itop-backup.php" + ], + "webservice": [], + "dictionary": [ + "en.dict.itop-backup.php", + "fr.dict.itop-backup.php", + "2.x\/itop-backup\/dictionaries\/cs.dict.itop-backup.php", + "2.x\/itop-backup\/dictionaries\/es_cr.dict.itop-backup.php", + "2.x\/itop-backup\/dictionaries\/pl.dict.itop-backup.php", + "2.x\/itop-backup\/dictionaries\/fr.dict.itop-backup.php", + "2.x\/itop-backup\/dictionaries\/de.dict.itop-backup.php", + "2.x\/itop-backup\/dictionaries\/ja.dict.itop-backup.php", + "2.x\/itop-backup\/dictionaries\/en.dict.itop-backup.php", + "2.x\/itop-backup\/dictionaries\/hu.dict.itop-backup.php", + "2.x\/itop-backup\/dictionaries\/nl.dict.itop-backup.php", + "2.x\/itop-backup\/dictionaries\/it.dict.itop-backup.php", + "2.x\/itop-backup\/dictionaries\/sk.dict.itop-backup.php", + "2.x\/itop-backup\/dictionaries\/ru.dict.itop-backup.php", + "2.x\/itop-backup\/dictionaries\/tr.dict.itop-backup.php", + "2.x\/itop-backup\/dictionaries\/pt_br.dict.itop-backup.php", + "2.x\/itop-backup\/dictionaries\/en_gb.dict.itop-backup.php", + "2.x\/itop-backup\/dictionaries\/da.dict.itop-backup.php", + "2.x\/itop-backup\/dictionaries\/zh_cn.dict.itop-backup.php" + ], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": { + "mysql_bindir": "", + "week_days": "monday, tuesday, wednesday, thursday, friday", + "time": "23:30", + "retention_count": 5, + "enabled": true, + "itop_backup_incident": "" + }, + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-backup\/module.itop-backup.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-backup", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-backup\/module.itop-backup.php", + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 2, + "message": "the module is part of the application" + }, + "uninstall": { + "flag": 3, + "message": "the module is part of the application" + } + }, + "itop-config": { + "label": "Configuration editor", + "category": "Application management", + "dependencies": [], + "mandatory": true, + "visible": false, + "datamodel": [ + "src\/Validator\/ConfigNodesVisitor.php", + "src\/Validator\/iTopConfigAstValidator.php", + "src\/Validator\/iTopConfigSyntaxValidator.php", + "src\/Validator\/iTopConfigValidator.php", + "src\/Controller\/ConfigEditorController.php" + ], + "webservice": [], + "dictionary": [ + "en.dict.itop-config.php", + "fr.dict.itop-config.php", + "2.x\/itop-config\/dictionaries\/pl.dict.itop-config.php", + "2.x\/itop-config\/dictionaries\/ru.dict.itop-config.php", + "2.x\/itop-config\/dictionaries\/en.dict.itop-config.php", + "2.x\/itop-config\/dictionaries\/sk.dict.itop-config.php", + "2.x\/itop-config\/dictionaries\/en_gb.dict.itop-config.php", + "2.x\/itop-config\/dictionaries\/cs.dict.itop-config.php", + "2.x\/itop-config\/dictionaries\/de.dict.itop-config.php", + "2.x\/itop-config\/dictionaries\/zh_cn.dict.itop-config.php", + "2.x\/itop-config\/dictionaries\/nl.dict.itop-config.php", + "2.x\/itop-config\/dictionaries\/es_cr.dict.itop-config.php", + "2.x\/itop-config\/dictionaries\/da.dict.itop-config.php", + "2.x\/itop-config\/dictionaries\/ja.dict.itop-config.php", + "2.x\/itop-config\/dictionaries\/pt_br.dict.itop-config.php", + "2.x\/itop-config\/dictionaries\/tr.dict.itop-config.php", + "2.x\/itop-config\/dictionaries\/hu.dict.itop-config.php", + "2.x\/itop-config\/dictionaries\/it.dict.itop-config.php", + "2.x\/itop-config\/dictionaries\/fr.dict.itop-config.php" + ], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-config\/module.itop-config.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-config", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-config\/module.itop-config.php", + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 2, + "message": "the module is part of the application" + }, + "uninstall": { + "flag": 3, + "message": "the module is part of the application" + } + }, + "itop-files-information": { + "label": "iTop files information", + "category": "business", + "dependencies": [], + "mandatory": false, + "visible": false, + "datamodel": [ + "src\/Service\/FilesInformation.php", + "src\/Service\/FilesInformationException.php", + "src\/Service\/FilesInformationUtils.php", + "src\/Service\/FilesIntegrity.php" + ], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-files-information\/module.itop-files-information.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-files-information", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-files-information\/module.itop-files-information.php", + "dictionary": [ + "2.x\/itop-files-information\/dictionaries\/sk.dict.itop-files-information.php", + "2.x\/itop-files-information\/dictionaries\/cs.dict.itop-files-information.php", + "2.x\/itop-files-information\/dictionaries\/ja.dict.itop-files-information.php", + "2.x\/itop-files-information\/dictionaries\/hu.dict.itop-files-information.php", + "2.x\/itop-files-information\/dictionaries\/en_gb.dict.itop-files-information.php", + "2.x\/itop-files-information\/dictionaries\/fr.dict.itop-files-information.php", + "2.x\/itop-files-information\/dictionaries\/pt_br.dict.itop-files-information.php", + "2.x\/itop-files-information\/dictionaries\/es_cr.dict.itop-files-information.php", + "2.x\/itop-files-information\/dictionaries\/tr.dict.itop-files-information.php", + "2.x\/itop-files-information\/dictionaries\/pl.dict.itop-files-information.php", + "2.x\/itop-files-information\/dictionaries\/zh_cn.dict.itop-files-information.php", + "2.x\/itop-files-information\/dictionaries\/en.dict.itop-files-information.php", + "2.x\/itop-files-information\/dictionaries\/da.dict.itop-files-information.php", + "2.x\/itop-files-information\/dictionaries\/de.dict.itop-files-information.php", + "2.x\/itop-files-information\/dictionaries\/nl.dict.itop-files-information.php", + "2.x\/itop-files-information\/dictionaries\/it.dict.itop-files-information.php", + "2.x\/itop-files-information\/dictionaries\/ru.dict.itop-files-information.php" + ], + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 1, + "message": "" + }, + "uninstall": { + "flag": 1, + "message": "" + } + }, + "itop-portal-base": { + "label": "Portal Development Library", + "category": "Portal", + "dependencies": [], + "mandatory": true, + "visible": false, + "datamodel": [ + "portal\/vendor\/autoload.php" + ], + "webservice": [], + "dictionary": [ + "2.x\/itop-portal-base\/dictionaries\/en_gb.dict.itop-portal-base.php", + "2.x\/itop-portal-base\/dictionaries\/hu.dict.itop-portal-base.php", + "2.x\/itop-portal-base\/dictionaries\/ja.dict.itop-portal-base.php", + "2.x\/itop-portal-base\/dictionaries\/cs.dict.itop-portal-base.php", + "2.x\/itop-portal-base\/dictionaries\/zh_cn.dict.itop-portal-base.php", + "2.x\/itop-portal-base\/dictionaries\/tr.dict.itop-portal-base.php", + "2.x\/itop-portal-base\/dictionaries\/pt_br.dict.itop-portal-base.php", + "2.x\/itop-portal-base\/dictionaries\/nl.dict.itop-portal-base.php", + "2.x\/itop-portal-base\/dictionaries\/it.dict.itop-portal-base.php", + "2.x\/itop-portal-base\/dictionaries\/es_cr.dict.itop-portal-base.php", + "2.x\/itop-portal-base\/dictionaries\/fr.dict.itop-portal-base.php", + "2.x\/itop-portal-base\/dictionaries\/pl.dict.itop-portal-base.php", + "2.x\/itop-portal-base\/dictionaries\/ru.dict.itop-portal-base.php", + "2.x\/itop-portal-base\/dictionaries\/de.dict.itop-portal-base.php", + "2.x\/itop-portal-base\/dictionaries\/da.dict.itop-portal-base.php", + "2.x\/itop-portal-base\/dictionaries\/en.dict.itop-portal-base.php", + "2.x\/itop-portal-base\/dictionaries\/sk.dict.itop-portal-base.php" + ], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-portal-base\/module.itop-portal-base.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-portal-base", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-portal-base\/module.itop-portal-base.php", + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 2, + "message": "the module is part of the application" + }, + "uninstall": { + "flag": 3, + "message": "the module is part of the application" + } + }, + "itop-portal": { + "label": "Enhanced Customer Portal", + "category": "Portal", + "dependencies": [ + "itop-portal-base\/2.7.0" + ], + "mandatory": false, + "visible": true, + "datamodel": [ + "main.itop-portal.php" + ], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-portal\/module.itop-portal.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-portal", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-portal\/module.itop-portal.php", + "dictionary": [ + "2.x\/itop-portal\/dictionaries\/de.dict.itop-portal.php", + "2.x\/itop-portal\/dictionaries\/ru.dict.itop-portal.php", + "2.x\/itop-portal\/dictionaries\/pl.dict.itop-portal.php", + "2.x\/itop-portal\/dictionaries\/ja.dict.itop-portal.php", + "2.x\/itop-portal\/dictionaries\/cs.dict.itop-portal.php", + "2.x\/itop-portal\/dictionaries\/zh_cn.dict.itop-portal.php", + "2.x\/itop-portal\/dictionaries\/en_gb.dict.itop-portal.php", + "2.x\/itop-portal\/dictionaries\/da.dict.itop-portal.php", + "2.x\/itop-portal\/dictionaries\/hu.dict.itop-portal.php", + "2.x\/itop-portal\/dictionaries\/it.dict.itop-portal.php", + "2.x\/itop-portal\/dictionaries\/tr.dict.itop-portal.php", + "2.x\/itop-portal\/dictionaries\/es_cr.dict.itop-portal.php", + "2.x\/itop-portal\/dictionaries\/sk.dict.itop-portal.php", + "2.x\/itop-portal\/dictionaries\/fr.dict.itop-portal.php", + "2.x\/itop-portal\/dictionaries\/nl.dict.itop-portal.php", + "2.x\/itop-portal\/dictionaries\/pt_br.dict.itop-portal.php", + "2.x\/itop-portal\/dictionaries\/en.dict.itop-portal.php" + ], + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 1, + "message": "" + }, + "uninstall": { + "flag": 1, + "message": "" + } + }, + "itop-profiles-itil": { + "label": "Create standard ITIL profiles", + "category": "create_profiles", + "dependencies": [], + "mandatory": true, + "visible": false, + "datamodel": [], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-profiles-itil\/module.itop-profiles-itil.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-profiles-itil", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-profiles-itil\/module.itop-profiles-itil.php", + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 2, + "message": "the module is part of the application" + }, + "uninstall": { + "flag": 3, + "message": "the module is part of the application" + } + }, + "itop-sla-computation": { + "label": "SLA Computation", + "category": "sla", + "dependencies": [], + "mandatory": true, + "visible": false, + "datamodel": [ + "main.itop-sla-computation.php" + ], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-sla-computation\/module.itop-sla-computation.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-sla-computation", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-sla-computation\/module.itop-sla-computation.php", + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 2, + "message": "the module is part of the application" + }, + "uninstall": { + "flag": 3, + "message": "the module is part of the application" + } + }, + "itop-structure": { + "label": "Core iTop Structure", + "category": "business", + "dependencies": [], + "mandatory": true, + "visible": false, + "installer": "StructureInstaller", + "datamodel": [ + "main.itop-structure.php" + ], + "data.struct": [], + "data.sample": [ + "data.sample.organizations.xml", + "data.sample.locations.xml", + "data.sample.persons.xml", + "data.sample.teams.xml", + "data.sample.contactteam.xml", + "data.sample.contacttype.xml" + ], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-structure\/module.itop-structure.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-structure", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-structure\/module.itop-structure.php", + "dictionary": [ + "2.x\/itop-structure\/dictionaries\/sk.dict.itop-structure.php", + "2.x\/itop-structure\/dictionaries\/pl.dict.itop-structure.php", + "2.x\/itop-structure\/dictionaries\/fr.dict.itop-structure.php", + "2.x\/itop-structure\/dictionaries\/pt_br.dict.itop-structure.php", + "2.x\/itop-structure\/dictionaries\/da.dict.itop-structure.php", + "2.x\/itop-structure\/dictionaries\/ja.dict.itop-structure.php", + "2.x\/itop-structure\/dictionaries\/ru.dict.itop-structure.php", + "2.x\/itop-structure\/dictionaries\/tr.dict.itop-structure.php", + "2.x\/itop-structure\/dictionaries\/hu.dict.itop-structure.php", + "2.x\/itop-structure\/dictionaries\/nl.dict.itop-structure.php", + "2.x\/itop-structure\/dictionaries\/en_gb.dict.itop-structure.php", + "2.x\/itop-structure\/dictionaries\/en.dict.itop-structure.php", + "2.x\/itop-structure\/dictionaries\/it.dict.itop-structure.php", + "2.x\/itop-structure\/dictionaries\/de.dict.itop-structure.php", + "2.x\/itop-structure\/dictionaries\/cs.dict.itop-structure.php", + "2.x\/itop-structure\/dictionaries\/es_cr.dict.itop-structure.php", + "2.x\/itop-structure\/dictionaries\/zh_cn.dict.itop-structure.php" + ], + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 2, + "message": "the module is part of the application" + }, + "uninstall": { + "flag": 3, + "message": "the module is part of the application" + } + }, + "itop-themes-compat": { + "label": "Light grey and Test red themes compatibility", + "category": "business", + "dependencies": [ + "itop-structure\/3.1.0" + ], + "mandatory": false, + "visible": true, + "datamodel": [], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-themes-compat\/module.itop-themes-compat.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-themes-compat", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-themes-compat\/module.itop-themes-compat.php", + "dictionary": [ + "2.x\/itop-themes-compat\/dictionaries\/it.dict.itop-themes-compat.php", + "2.x\/itop-themes-compat\/dictionaries\/tr.dict.itop-themes-compat.php", + "2.x\/itop-themes-compat\/dictionaries\/ru.dict.itop-themes-compat.php", + "2.x\/itop-themes-compat\/dictionaries\/pt_br.dict.itop-themes-compat.php", + "2.x\/itop-themes-compat\/dictionaries\/da.dict.itop-themes-compat.php", + "2.x\/itop-themes-compat\/dictionaries\/fr.dict.itop-themes-compat.php", + "2.x\/itop-themes-compat\/dictionaries\/ja.dict.itop-themes-compat.php", + "2.x\/itop-themes-compat\/dictionaries\/hu.dict.itop-themes-compat.php", + "2.x\/itop-themes-compat\/dictionaries\/en_gb.dict.itop-themes-compat.php", + "2.x\/itop-themes-compat\/dictionaries\/cs.dict.itop-themes-compat.php", + "2.x\/itop-themes-compat\/dictionaries\/nl.dict.itop-themes-compat.php", + "2.x\/itop-themes-compat\/dictionaries\/sk.dict.itop-themes-compat.php", + "2.x\/itop-themes-compat\/dictionaries\/de.dict.itop-themes-compat.php", + "2.x\/itop-themes-compat\/dictionaries\/es_cr.dict.itop-themes-compat.php", + "2.x\/itop-themes-compat\/dictionaries\/zh_cn.dict.itop-themes-compat.php", + "2.x\/itop-themes-compat\/dictionaries\/pl.dict.itop-themes-compat.php", + "2.x\/itop-themes-compat\/dictionaries\/en.dict.itop-themes-compat.php" + ], + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 1, + "message": "" + }, + "uninstall": { + "flag": 1, + "message": "" + } + }, + "itop-tickets": { + "label": "Tickets Management", + "category": "business", + "dependencies": [ + "itop-structure\/2.7.1" + ], + "mandatory": false, + "visible": true, + "installer": "TicketsInstaller", + "datamodel": [ + "main.itop-tickets.php" + ], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-tickets\/module.itop-tickets.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-tickets", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-tickets\/module.itop-tickets.php", + "dictionary": [ + "2.x\/itop-tickets\/dictionaries\/cs.dict.itop-tickets.php", + "2.x\/itop-tickets\/dictionaries\/da.dict.itop-tickets.php", + "2.x\/itop-tickets\/dictionaries\/es_cr.dict.itop-tickets.php", + "2.x\/itop-tickets\/dictionaries\/tr.dict.itop-tickets.php", + "2.x\/itop-tickets\/dictionaries\/nl.dict.itop-tickets.php", + "2.x\/itop-tickets\/dictionaries\/pl.dict.itop-tickets.php", + "2.x\/itop-tickets\/dictionaries\/it.dict.itop-tickets.php", + "2.x\/itop-tickets\/dictionaries\/en.dict.itop-tickets.php", + "2.x\/itop-tickets\/dictionaries\/pt_br.dict.itop-tickets.php", + "2.x\/itop-tickets\/dictionaries\/fr.dict.itop-tickets.php", + "2.x\/itop-tickets\/dictionaries\/sk.dict.itop-tickets.php", + "2.x\/itop-tickets\/dictionaries\/ja.dict.itop-tickets.php", + "2.x\/itop-tickets\/dictionaries\/ru.dict.itop-tickets.php", + "2.x\/itop-tickets\/dictionaries\/hu.dict.itop-tickets.php", + "2.x\/itop-tickets\/dictionaries\/de.dict.itop-tickets.php", + "2.x\/itop-tickets\/dictionaries\/en_gb.dict.itop-tickets.php", + "2.x\/itop-tickets\/dictionaries\/zh_cn.dict.itop-tickets.php" + ], + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 1, + "message": "" + }, + "uninstall": { + "flag": 1, + "message": "" + } + }, + "itop-welcome-itil": { + "label": "ITIL skin", + "category": "skin", + "dependencies": [], + "mandatory": true, + "visible": false, + "datamodel": [], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-welcome-itil\/module.itop-welcome-itil.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-welcome-itil", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-welcome-itil\/module.itop-welcome-itil.php", + "dictionary": [ + "2.x\/itop-welcome-itil\/dictionaries\/da.dict.itop-welcome-itil.php", + "2.x\/itop-welcome-itil\/dictionaries\/es_cr.dict.itop-welcome-itil.php", + "2.x\/itop-welcome-itil\/dictionaries\/sk.dict.itop-welcome-itil.php", + "2.x\/itop-welcome-itil\/dictionaries\/nl.dict.itop-welcome-itil.php", + "2.x\/itop-welcome-itil\/dictionaries\/en.dict.itop-welcome-itil.php", + "2.x\/itop-welcome-itil\/dictionaries\/fr.dict.itop-welcome-itil.php", + "2.x\/itop-welcome-itil\/dictionaries\/ru.dict.itop-welcome-itil.php", + "2.x\/itop-welcome-itil\/dictionaries\/ja.dict.itop-welcome-itil.php", + "2.x\/itop-welcome-itil\/dictionaries\/de.dict.itop-welcome-itil.php", + "2.x\/itop-welcome-itil\/dictionaries\/it.dict.itop-welcome-itil.php", + "2.x\/itop-welcome-itil\/dictionaries\/pl.dict.itop-welcome-itil.php", + "2.x\/itop-welcome-itil\/dictionaries\/tr.dict.itop-welcome-itil.php", + "2.x\/itop-welcome-itil\/dictionaries\/en_gb.dict.itop-welcome-itil.php", + "2.x\/itop-welcome-itil\/dictionaries\/hu.dict.itop-welcome-itil.php", + "2.x\/itop-welcome-itil\/dictionaries\/zh_cn.dict.itop-welcome-itil.php", + "2.x\/itop-welcome-itil\/dictionaries\/cs.dict.itop-welcome-itil.php", + "2.x\/itop-welcome-itil\/dictionaries\/pt_br.dict.itop-welcome-itil.php" + ], + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 2, + "message": "the module is part of the application" + }, + "uninstall": { + "flag": 3, + "message": "the module is part of the application" + } + }, + "combodo-db-tools": { + "label": "Database maintenance tools", + "category": "business", + "dependencies": [ + "itop-structure\/3.0.0" + ], + "mandatory": false, + "visible": true, + "datamodel": [ + "src\/Service\/DBToolsUtils.php", + "src\/Service\/DBAnalyzerUtils.php" + ], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/combodo-db-tools\/module.combodo-db-tools.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/combodo-db-tools", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/combodo-db-tools\/module.combodo-db-tools.php", + "dictionary": [ + "2.x\/combodo-db-tools\/dictionaries\/en.dict.combodo-db-tools.php", + "2.x\/combodo-db-tools\/dictionaries\/pl.dict.combodo-db-tools.php", + "2.x\/combodo-db-tools\/dictionaries\/pt_br.dict.combodo-db-tools.php", + "2.x\/combodo-db-tools\/dictionaries\/zh_cn.dict.combodo-db-tools.php", + "2.x\/combodo-db-tools\/dictionaries\/en_gb.dict.combodo-db-tools.php", + "2.x\/combodo-db-tools\/dictionaries\/nl.dict.combodo-db-tools.php", + "2.x\/combodo-db-tools\/dictionaries\/ru.dict.combodo-db-tools.php", + "2.x\/combodo-db-tools\/dictionaries\/es_cr.dict.combodo-db-tools.php", + "2.x\/combodo-db-tools\/dictionaries\/tr.dict.combodo-db-tools.php", + "2.x\/combodo-db-tools\/dictionaries\/da.dict.combodo-db-tools.php", + "2.x\/combodo-db-tools\/dictionaries\/ja.dict.combodo-db-tools.php", + "2.x\/combodo-db-tools\/dictionaries\/de.dict.combodo-db-tools.php", + "2.x\/combodo-db-tools\/dictionaries\/hu.dict.combodo-db-tools.php", + "2.x\/combodo-db-tools\/dictionaries\/fr.dict.combodo-db-tools.php", + "2.x\/combodo-db-tools\/dictionaries\/it.dict.combodo-db-tools.php", + "2.x\/combodo-db-tools\/dictionaries\/sk.dict.combodo-db-tools.php", + "2.x\/combodo-db-tools\/dictionaries\/cs.dict.combodo-db-tools.php" + ], + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 1, + "message": "" + }, + "uninstall": { + "flag": 1, + "message": "" + } + }, + "itop-config-mgmt": { + "label": "Configuration Management (CMDB)", + "category": "business", + "dependencies": [ + "itop-structure\/2.7.1" + ], + "mandatory": false, + "visible": true, + "installer": "ConfigMgmtInstaller", + "datamodel": [ + "model.itop-config-mgmt.php", + "main.itop-config-mgmt.php" + ], + "data.struct": [ + "data\/en_us.data.itop-brand.xml", + "data\/en_us.data.itop-osfamily.xml", + "data\/en_us.data.itop-osversion.xml" + ], + "data.sample": [ + "data.sample.model.xml", + "data.sample.networkdevicetype.xml", + "data.sample.servers.xml", + "data.sample.nw-devices.xml", + "data.sample.software.xml", + "data.sample.dbserver.xml", + "data.sample.dbschema.xml", + "data.sample.webserver.xml", + "data.sample.webapp.xml", + "data.sample.applications.xml", + "data.sample.applicationsolutionci.xml" + ], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-config-mgmt\/module.itop-config-mgmt.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-config-mgmt", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-config-mgmt\/module.itop-config-mgmt.php", + "dictionary": [ + "2.x\/itop-config-mgmt\/dictionaries\/ru.dict.itop-config-mgmt.php", + "2.x\/itop-config-mgmt\/dictionaries\/tr.dict.itop-config-mgmt.php", + "2.x\/itop-config-mgmt\/dictionaries\/it.dict.itop-config-mgmt.php", + "2.x\/itop-config-mgmt\/dictionaries\/pl.dict.itop-config-mgmt.php", + "2.x\/itop-config-mgmt\/dictionaries\/de.dict.itop-config-mgmt.php", + "2.x\/itop-config-mgmt\/dictionaries\/en_gb.dict.itop-config-mgmt.php", + "2.x\/itop-config-mgmt\/dictionaries\/fr.dict.itop-config-mgmt.php", + "2.x\/itop-config-mgmt\/dictionaries\/hu.dict.itop-config-mgmt.php", + "2.x\/itop-config-mgmt\/dictionaries\/nl.dict.itop-config-mgmt.php", + "2.x\/itop-config-mgmt\/dictionaries\/en.dict.itop-config-mgmt.php", + "2.x\/itop-config-mgmt\/dictionaries\/cs.dict.itop-config-mgmt.php", + "2.x\/itop-config-mgmt\/dictionaries\/ja.dict.itop-config-mgmt.php", + "2.x\/itop-config-mgmt\/dictionaries\/sk.dict.itop-config-mgmt.php", + "2.x\/itop-config-mgmt\/dictionaries\/zh_cn.dict.itop-config-mgmt.php", + "2.x\/itop-config-mgmt\/dictionaries\/da.dict.itop-config-mgmt.php", + "2.x\/itop-config-mgmt\/dictionaries\/pt_br.dict.itop-config-mgmt.php", + "2.x\/itop-config-mgmt\/dictionaries\/es_cr.dict.itop-config-mgmt.php" + ], + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 1, + "message": "" + }, + "uninstall": { + "flag": 1, + "message": "" + } + }, + "itop-core-update": { + "label": "iTop Core Update", + "category": "business", + "dependencies": [ + "itop-files-information\/2.7.0", + "combodo-db-tools\/2.7.0" + ], + "mandatory": false, + "visible": true, + "datamodel": [ + "src\/Service\/RunTimeEnvironmentCoreUpdater.php", + "src\/Service\/CoreUpdater.php", + "src\/Controller\/UpdateController.php", + "src\/Controller\/AjaxController.php" + ], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-core-update\/module.itop-core-update.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-core-update", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-core-update\/module.itop-core-update.php", + "dictionary": [ + "2.x\/itop-core-update\/dictionaries\/ru.dict.itop-core-update.php", + "2.x\/itop-core-update\/dictionaries\/de.dict.itop-core-update.php", + "2.x\/itop-core-update\/dictionaries\/hu.dict.itop-core-update.php", + "2.x\/itop-core-update\/dictionaries\/es_cr.dict.itop-core-update.php", + "2.x\/itop-core-update\/dictionaries\/cs.dict.itop-core-update.php", + "2.x\/itop-core-update\/dictionaries\/sk.dict.itop-core-update.php", + "2.x\/itop-core-update\/dictionaries\/pl.dict.itop-core-update.php", + "2.x\/itop-core-update\/dictionaries\/zh_cn.dict.itop-core-update.php", + "2.x\/itop-core-update\/dictionaries\/fr.dict.itop-core-update.php", + "2.x\/itop-core-update\/dictionaries\/da.dict.itop-core-update.php", + "2.x\/itop-core-update\/dictionaries\/en_gb.dict.itop-core-update.php", + "2.x\/itop-core-update\/dictionaries\/it.dict.itop-core-update.php", + "2.x\/itop-core-update\/dictionaries\/pt_br.dict.itop-core-update.php", + "2.x\/itop-core-update\/dictionaries\/en.dict.itop-core-update.php", + "2.x\/itop-core-update\/dictionaries\/nl.dict.itop-core-update.php", + "2.x\/itop-core-update\/dictionaries\/tr.dict.itop-core-update.php", + "2.x\/itop-core-update\/dictionaries\/ja.dict.itop-core-update.php" + ], + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 1, + "message": "" + }, + "uninstall": { + "flag": 1, + "message": "" + } + }, + "itop-datacenter-mgmt": { + "label": "Datacenter Management", + "category": "business", + "dependencies": [ + "itop-config-mgmt\/2.2.0" + ], + "mandatory": false, + "visible": true, + "datamodel": [], + "webservice": [], + "data.struct": [], + "data.sample": [ + "data.sample.racks.xml" + ], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-datacenter-mgmt\/module.itop-datacenter-mgmt.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-datacenter-mgmt", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-datacenter-mgmt\/module.itop-datacenter-mgmt.php", + "dictionary": [ + "2.x\/itop-datacenter-mgmt\/dictionaries\/tr.dict.itop-datacenter-mgmt.php", + "2.x\/itop-datacenter-mgmt\/dictionaries\/ja.dict.itop-datacenter-mgmt.php", + "2.x\/itop-datacenter-mgmt\/dictionaries\/sk.dict.itop-datacenter-mgmt.php", + "2.x\/itop-datacenter-mgmt\/dictionaries\/da.dict.itop-datacenter-mgmt.php", + "2.x\/itop-datacenter-mgmt\/dictionaries\/es_cr.dict.itop-datacenter-mgmt.php", + "2.x\/itop-datacenter-mgmt\/dictionaries\/pl.dict.itop-datacenter-mgmt.php", + "2.x\/itop-datacenter-mgmt\/dictionaries\/ru.dict.itop-datacenter-mgmt.php", + "2.x\/itop-datacenter-mgmt\/dictionaries\/en.dict.itop-datacenter-mgmt.php", + "2.x\/itop-datacenter-mgmt\/dictionaries\/it.dict.itop-datacenter-mgmt.php", + "2.x\/itop-datacenter-mgmt\/dictionaries\/zh_cn.dict.itop-datacenter-mgmt.php", + "2.x\/itop-datacenter-mgmt\/dictionaries\/de.dict.itop-datacenter-mgmt.php", + "2.x\/itop-datacenter-mgmt\/dictionaries\/hu.dict.itop-datacenter-mgmt.php", + "2.x\/itop-datacenter-mgmt\/dictionaries\/cs.dict.itop-datacenter-mgmt.php", + "2.x\/itop-datacenter-mgmt\/dictionaries\/en_gb.dict.itop-datacenter-mgmt.php", + "2.x\/itop-datacenter-mgmt\/dictionaries\/fr.dict.itop-datacenter-mgmt.php", + "2.x\/itop-datacenter-mgmt\/dictionaries\/pt_br.dict.itop-datacenter-mgmt.php", + "2.x\/itop-datacenter-mgmt\/dictionaries\/nl.dict.itop-datacenter-mgmt.php" + ], + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 1, + "message": "" + }, + "uninstall": { + "flag": 1, + "message": "" + } + }, + "itop-endusers-devices": { + "label": "End-user Devices Management", + "category": "business", + "dependencies": [ + "itop-config-mgmt\/2.2.0" + ], + "mandatory": false, + "visible": true, + "installer": "EndUserMgmtInstaller", + "datamodel": [], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-endusers-devices\/module.itop-endusers-devices.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-endusers-devices", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-endusers-devices\/module.itop-endusers-devices.php", + "dictionary": [ + "2.x\/itop-endusers-devices\/dictionaries\/pl.dict.itop-endusers-devices.php", + "2.x\/itop-endusers-devices\/dictionaries\/cs.dict.itop-endusers-devices.php", + "2.x\/itop-endusers-devices\/dictionaries\/en.dict.itop-endusers-devices.php", + "2.x\/itop-endusers-devices\/dictionaries\/ru.dict.itop-endusers-devices.php", + "2.x\/itop-endusers-devices\/dictionaries\/it.dict.itop-endusers-devices.php", + "2.x\/itop-endusers-devices\/dictionaries\/en_gb.dict.itop-endusers-devices.php", + "2.x\/itop-endusers-devices\/dictionaries\/sk.dict.itop-endusers-devices.php", + "2.x\/itop-endusers-devices\/dictionaries\/es_cr.dict.itop-endusers-devices.php", + "2.x\/itop-endusers-devices\/dictionaries\/de.dict.itop-endusers-devices.php", + "2.x\/itop-endusers-devices\/dictionaries\/fr.dict.itop-endusers-devices.php", + "2.x\/itop-endusers-devices\/dictionaries\/tr.dict.itop-endusers-devices.php", + "2.x\/itop-endusers-devices\/dictionaries\/hu.dict.itop-endusers-devices.php", + "2.x\/itop-endusers-devices\/dictionaries\/da.dict.itop-endusers-devices.php", + "2.x\/itop-endusers-devices\/dictionaries\/zh_cn.dict.itop-endusers-devices.php", + "2.x\/itop-endusers-devices\/dictionaries\/nl.dict.itop-endusers-devices.php", + "2.x\/itop-endusers-devices\/dictionaries\/ja.dict.itop-endusers-devices.php", + "2.x\/itop-endusers-devices\/dictionaries\/pt_br.dict.itop-endusers-devices.php" + ], + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 1, + "message": "" + }, + "uninstall": { + "flag": 1, + "message": "" + } + }, + "itop-faq-light": { + "label": "Frequently Asked Questions Database", + "category": "business", + "dependencies": [ + "itop-structure\/3.0.0 || itop-portal\/3.0.0" + ], + "mandatory": false, + "visible": true, + "installer": "FAQLightInstaller", + "datamodel": [], + "data.struct": [], + "data.sample": [ + "data.sample.faq-domains.xml" + ], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-faq-light\/module.itop-faq-light.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-faq-light", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-faq-light\/module.itop-faq-light.php", + "dictionary": [ + "2.x\/itop-faq-light\/dictionaries\/pl.dict.itop-faq-light.php", + "2.x\/itop-faq-light\/dictionaries\/da.dict.itop-faq-light.php", + "2.x\/itop-faq-light\/dictionaries\/en.dict.itop-faq-light.php", + "2.x\/itop-faq-light\/dictionaries\/zh_cn.dict.itop-faq-light.php", + "2.x\/itop-faq-light\/dictionaries\/es_cr.dict.itop-faq-light.php", + "2.x\/itop-faq-light\/dictionaries\/nl.dict.itop-faq-light.php", + "2.x\/itop-faq-light\/dictionaries\/pt_br.dict.itop-faq-light.php", + "2.x\/itop-faq-light\/dictionaries\/cs.dict.itop-faq-light.php", + "2.x\/itop-faq-light\/dictionaries\/ru.dict.itop-faq-light.php", + "2.x\/itop-faq-light\/dictionaries\/en_gb.dict.itop-faq-light.php", + "2.x\/itop-faq-light\/dictionaries\/tr.dict.itop-faq-light.php", + "2.x\/itop-faq-light\/dictionaries\/it.dict.itop-faq-light.php", + "2.x\/itop-faq-light\/dictionaries\/fr.dict.itop-faq-light.php", + "2.x\/itop-faq-light\/dictionaries\/hu.dict.itop-faq-light.php", + "2.x\/itop-faq-light\/dictionaries\/sk.dict.itop-faq-light.php", + "2.x\/itop-faq-light\/dictionaries\/de.dict.itop-faq-light.php", + "2.x\/itop-faq-light\/dictionaries\/ja.dict.itop-faq-light.php" + ], + "installed_version": "", + "available_version": "3.3.0", + "install": { + "flag": 1, + "message": "" + } + }, + "itop-hub-connector": { + "label": "iTop Hub Connector", + "category": "business", + "dependencies": [ + "itop-config-mgmt\/2.4.0" + ], + "mandatory": false, + "visible": true, + "datamodel": [ + "menus.php", + "hubnewsroomprovider.class.inc.php" + ], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-hub-connector\/module.itop-hub-connector.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-hub-connector", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-hub-connector\/module.itop-hub-connector.php", + "dictionary": [ + "2.x\/itop-hub-connector\/dictionaries\/en_gb.dict.itop-hub-connector.php", + "2.x\/itop-hub-connector\/dictionaries\/it.dict.itop-hub-connector.php", + "2.x\/itop-hub-connector\/dictionaries\/zh_cn.dict.itop-hub-connector.php", + "2.x\/itop-hub-connector\/dictionaries\/sk.dict.itop-hub-connector.php", + "2.x\/itop-hub-connector\/dictionaries\/cs.dict.itop-hub-connector.php", + "2.x\/itop-hub-connector\/dictionaries\/fr.dict.itop-hub-connector.php", + "2.x\/itop-hub-connector\/dictionaries\/hu.dict.itop-hub-connector.php", + "2.x\/itop-hub-connector\/dictionaries\/ru.dict.itop-hub-connector.php", + "2.x\/itop-hub-connector\/dictionaries\/ja.dict.itop-hub-connector.php", + "2.x\/itop-hub-connector\/dictionaries\/en.dict.itop-hub-connector.php", + "2.x\/itop-hub-connector\/dictionaries\/es_cr.dict.itop-hub-connector.php", + "2.x\/itop-hub-connector\/dictionaries\/tr.dict.itop-hub-connector.php", + "2.x\/itop-hub-connector\/dictionaries\/nl.dict.itop-hub-connector.php", + "2.x\/itop-hub-connector\/dictionaries\/pl.dict.itop-hub-connector.php", + "2.x\/itop-hub-connector\/dictionaries\/de.dict.itop-hub-connector.php", + "2.x\/itop-hub-connector\/dictionaries\/pt_br.dict.itop-hub-connector.php", + "2.x\/itop-hub-connector\/dictionaries\/da.dict.itop-hub-connector.php" + ], + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 1, + "message": "" + }, + "uninstall": { + "flag": 1, + "message": "" + } + }, + "itop-incident-mgmt-itil": { + "label": "Incident Management ITIL", + "category": "business", + "dependencies": [ + "itop-config-mgmt\/2.4.0", + "itop-tickets\/2.4.0", + "itop-profiles-itil\/2.3.0" + ], + "mandatory": false, + "visible": true, + "datamodel": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-incident-mgmt-itil\/module.itop-incident-mgmt-itil.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-incident-mgmt-itil", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-incident-mgmt-itil\/module.itop-incident-mgmt-itil.php", + "dictionary": [ + "2.x\/itop-incident-mgmt-itil\/dictionaries\/en_gb.dict.itop-incident-mgmt-itil.php", + "2.x\/itop-incident-mgmt-itil\/dictionaries\/da.dict.itop-incident-mgmt-itil.php", + "2.x\/itop-incident-mgmt-itil\/dictionaries\/en.dict.itop-incident-mgmt-itil.php", + "2.x\/itop-incident-mgmt-itil\/dictionaries\/de.dict.itop-incident-mgmt-itil.php", + "2.x\/itop-incident-mgmt-itil\/dictionaries\/zh_cn.dict.itop-incident-mgmt-itil.php", + "2.x\/itop-incident-mgmt-itil\/dictionaries\/sk.dict.itop-incident-mgmt-itil.php", + "2.x\/itop-incident-mgmt-itil\/dictionaries\/fr.dict.itop-incident-mgmt-itil.php", + "2.x\/itop-incident-mgmt-itil\/dictionaries\/hu.dict.itop-incident-mgmt-itil.php", + "2.x\/itop-incident-mgmt-itil\/dictionaries\/ja.dict.itop-incident-mgmt-itil.php", + "2.x\/itop-incident-mgmt-itil\/dictionaries\/pl.dict.itop-incident-mgmt-itil.php", + "2.x\/itop-incident-mgmt-itil\/dictionaries\/cs.dict.itop-incident-mgmt-itil.php", + "2.x\/itop-incident-mgmt-itil\/dictionaries\/nl.dict.itop-incident-mgmt-itil.php", + "2.x\/itop-incident-mgmt-itil\/dictionaries\/ru.dict.itop-incident-mgmt-itil.php", + "2.x\/itop-incident-mgmt-itil\/dictionaries\/tr.dict.itop-incident-mgmt-itil.php", + "2.x\/itop-incident-mgmt-itil\/dictionaries\/it.dict.itop-incident-mgmt-itil.php", + "2.x\/itop-incident-mgmt-itil\/dictionaries\/pt_br.dict.itop-incident-mgmt-itil.php", + "2.x\/itop-incident-mgmt-itil\/dictionaries\/es_cr.dict.itop-incident-mgmt-itil.php" + ], + "installed_version": "", + "available_version": "3.3.0", + "install": { + "flag": 1, + "message": "" + } + }, + "itop-knownerror-mgmt": { + "label": "Known Errors Database", + "category": "business", + "dependencies": [ + "itop-config-mgmt\/2.2.0" + ], + "mandatory": false, + "visible": true, + "datamodel": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-knownerror-mgmt\/module.itop-knownerror-mgmt.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-knownerror-mgmt", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-knownerror-mgmt\/module.itop-knownerror-mgmt.php", + "dictionary": [ + "2.x\/itop-knownerror-mgmt\/dictionaries\/hu.dict.itop-knownerror-mgmt.php", + "2.x\/itop-knownerror-mgmt\/dictionaries\/nl.dict.itop-knownerror-mgmt.php", + "2.x\/itop-knownerror-mgmt\/dictionaries\/cs.dict.itop-knownerror-mgmt.php", + "2.x\/itop-knownerror-mgmt\/dictionaries\/es_cr.dict.itop-knownerror-mgmt.php", + "2.x\/itop-knownerror-mgmt\/dictionaries\/fr.dict.itop-knownerror-mgmt.php", + "2.x\/itop-knownerror-mgmt\/dictionaries\/ru.dict.itop-knownerror-mgmt.php", + "2.x\/itop-knownerror-mgmt\/dictionaries\/en.dict.itop-knownerror-mgmt.php", + "2.x\/itop-knownerror-mgmt\/dictionaries\/da.dict.itop-knownerror-mgmt.php", + "2.x\/itop-knownerror-mgmt\/dictionaries\/it.dict.itop-knownerror-mgmt.php", + "2.x\/itop-knownerror-mgmt\/dictionaries\/sk.dict.itop-knownerror-mgmt.php", + "2.x\/itop-knownerror-mgmt\/dictionaries\/pt_br.dict.itop-knownerror-mgmt.php", + "2.x\/itop-knownerror-mgmt\/dictionaries\/tr.dict.itop-knownerror-mgmt.php", + "2.x\/itop-knownerror-mgmt\/dictionaries\/zh_cn.dict.itop-knownerror-mgmt.php", + "2.x\/itop-knownerror-mgmt\/dictionaries\/de.dict.itop-knownerror-mgmt.php", + "2.x\/itop-knownerror-mgmt\/dictionaries\/en_gb.dict.itop-knownerror-mgmt.php", + "2.x\/itop-knownerror-mgmt\/dictionaries\/pl.dict.itop-knownerror-mgmt.php", + "2.x\/itop-knownerror-mgmt\/dictionaries\/ja.dict.itop-knownerror-mgmt.php" + ], + "installed_version": "", + "available_version": "3.3.0", + "install": { + "flag": 1, + "message": "" + } + }, + "itop-oauth-client": { + "label": "OAuth 2.0 client", + "category": "business", + "dependencies": [ + "itop-welcome-itil\/3.1.0," + ], + "mandatory": false, + "visible": true, + "datamodel": [ + "vendor\/autoload.php", + "src\/Service\/PopupMenuExtension.php", + "src\/Service\/ApplicationUIExtension.php" + ], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-oauth-client\/module.itop-oauth-client.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-oauth-client", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-oauth-client\/module.itop-oauth-client.php", + "dictionary": [ + "2.x\/itop-oauth-client\/dictionaries\/tr.dict.itop-oauth-client.php", + "2.x\/itop-oauth-client\/dictionaries\/fr.dict.itop-oauth-client.php", + "2.x\/itop-oauth-client\/dictionaries\/it.dict.itop-oauth-client.php", + "2.x\/itop-oauth-client\/dictionaries\/en.dict.itop-oauth-client.php", + "2.x\/itop-oauth-client\/dictionaries\/cs.dict.itop-oauth-client.php", + "2.x\/itop-oauth-client\/dictionaries\/sk.dict.itop-oauth-client.php", + "2.x\/itop-oauth-client\/dictionaries\/pl.dict.itop-oauth-client.php", + "2.x\/itop-oauth-client\/dictionaries\/ru.dict.itop-oauth-client.php", + "2.x\/itop-oauth-client\/dictionaries\/zh_cn.dict.itop-oauth-client.php", + "2.x\/itop-oauth-client\/dictionaries\/pt_br.dict.itop-oauth-client.php", + "2.x\/itop-oauth-client\/dictionaries\/es_cr.dict.itop-oauth-client.php", + "2.x\/itop-oauth-client\/dictionaries\/nl.dict.itop-oauth-client.php", + "2.x\/itop-oauth-client\/dictionaries\/ja.dict.itop-oauth-client.php", + "2.x\/itop-oauth-client\/dictionaries\/de.dict.itop-oauth-client.php", + "2.x\/itop-oauth-client\/dictionaries\/hu.dict.itop-oauth-client.php", + "2.x\/itop-oauth-client\/dictionaries\/en_gb.dict.itop-oauth-client.php", + "2.x\/itop-oauth-client\/dictionaries\/da.dict.itop-oauth-client.php" + ], + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 1, + "message": "" + }, + "uninstall": { + "flag": 1, + "message": "" + } + }, + "itop-problem-mgmt": { + "label": "Problem Management", + "category": "business", + "dependencies": [ + "itop-tickets\/2.0.0" + ], + "mandatory": false, + "visible": true, + "datamodel": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-problem-mgmt\/module.itop-problem-mgmt.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-problem-mgmt", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-problem-mgmt\/module.itop-problem-mgmt.php", + "dictionary": [ + "2.x\/itop-problem-mgmt\/dictionaries\/tr.dict.itop-problem-mgmt.php", + "2.x\/itop-problem-mgmt\/dictionaries\/cs.dict.itop-problem-mgmt.php", + "2.x\/itop-problem-mgmt\/dictionaries\/sk.dict.itop-problem-mgmt.php", + "2.x\/itop-problem-mgmt\/dictionaries\/pt_br.dict.itop-problem-mgmt.php", + "2.x\/itop-problem-mgmt\/dictionaries\/es_cr.dict.itop-problem-mgmt.php", + "2.x\/itop-problem-mgmt\/dictionaries\/en_gb.dict.itop-problem-mgmt.php", + "2.x\/itop-problem-mgmt\/dictionaries\/da.dict.itop-problem-mgmt.php", + "2.x\/itop-problem-mgmt\/dictionaries\/ru.dict.itop-problem-mgmt.php", + "2.x\/itop-problem-mgmt\/dictionaries\/pl.dict.itop-problem-mgmt.php", + "2.x\/itop-problem-mgmt\/dictionaries\/en.dict.itop-problem-mgmt.php", + "2.x\/itop-problem-mgmt\/dictionaries\/hu.dict.itop-problem-mgmt.php", + "2.x\/itop-problem-mgmt\/dictionaries\/fr.dict.itop-problem-mgmt.php", + "2.x\/itop-problem-mgmt\/dictionaries\/nl.dict.itop-problem-mgmt.php", + "2.x\/itop-problem-mgmt\/dictionaries\/ja.dict.itop-problem-mgmt.php", + "2.x\/itop-problem-mgmt\/dictionaries\/de.dict.itop-problem-mgmt.php", + "2.x\/itop-problem-mgmt\/dictionaries\/zh_cn.dict.itop-problem-mgmt.php", + "2.x\/itop-problem-mgmt\/dictionaries\/it.dict.itop-problem-mgmt.php" + ], + "installed_version": "", + "available_version": "3.3.0", + "install": { + "flag": 1, + "message": "" + } + }, + "itop-request-mgmt-itil": { + "label": "User request Management ITIL", + "category": "business", + "dependencies": [ + "itop-tickets\/2.4.0" + ], + "mandatory": false, + "visible": true, + "datamodel": [ + "main.itop-request-mgmt-itil.php" + ], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-request-mgmt-itil\/module.itop-request-mgmt-itil.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-request-mgmt-itil", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-request-mgmt-itil\/module.itop-request-mgmt-itil.php", + "dictionary": [ + "2.x\/itop-request-mgmt-itil\/dictionaries\/ja.dict.itop-request-mgmt-itil.php", + "2.x\/itop-request-mgmt-itil\/dictionaries\/hu.dict.itop-request-mgmt-itil.php", + "2.x\/itop-request-mgmt-itil\/dictionaries\/fr.dict.itop-request-mgmt-itil.php", + "2.x\/itop-request-mgmt-itil\/dictionaries\/nl.dict.itop-request-mgmt-itil.php", + "2.x\/itop-request-mgmt-itil\/dictionaries\/ru.dict.itop-request-mgmt-itil.php", + "2.x\/itop-request-mgmt-itil\/dictionaries\/zh_cn.dict.itop-request-mgmt-itil.php", + "2.x\/itop-request-mgmt-itil\/dictionaries\/it.dict.itop-request-mgmt-itil.php", + "2.x\/itop-request-mgmt-itil\/dictionaries\/pl.dict.itop-request-mgmt-itil.php", + "2.x\/itop-request-mgmt-itil\/dictionaries\/pt_br.dict.itop-request-mgmt-itil.php", + "2.x\/itop-request-mgmt-itil\/dictionaries\/sk.dict.itop-request-mgmt-itil.php", + "2.x\/itop-request-mgmt-itil\/dictionaries\/tr.dict.itop-request-mgmt-itil.php", + "2.x\/itop-request-mgmt-itil\/dictionaries\/es_cr.dict.itop-request-mgmt-itil.php", + "2.x\/itop-request-mgmt-itil\/dictionaries\/en_gb.dict.itop-request-mgmt-itil.php", + "2.x\/itop-request-mgmt-itil\/dictionaries\/de.dict.itop-request-mgmt-itil.php", + "2.x\/itop-request-mgmt-itil\/dictionaries\/en.dict.itop-request-mgmt-itil.php", + "2.x\/itop-request-mgmt-itil\/dictionaries\/cs.dict.itop-request-mgmt-itil.php", + "2.x\/itop-request-mgmt-itil\/dictionaries\/da.dict.itop-request-mgmt-itil.php" + ], + "installed_version": "", + "available_version": "3.3.0", + "install": { + "flag": 1, + "message": "" + } + }, + "itop-request-mgmt": { + "label": "Simple Ticket Management", + "category": "business", + "dependencies": [ + "itop-tickets\/2.4.0" + ], + "mandatory": false, + "visible": true, + "datamodel": [ + "main.itop-request-mgmt.php" + ], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-request-mgmt\/module.itop-request-mgmt.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-request-mgmt", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-request-mgmt\/module.itop-request-mgmt.php", + "dictionary": [ + "2.x\/itop-request-mgmt\/dictionaries\/tr.dict.itop-request-mgmt.php", + "2.x\/itop-request-mgmt\/dictionaries\/da.dict.itop-request-mgmt.php", + "2.x\/itop-request-mgmt\/dictionaries\/it.dict.itop-request-mgmt.php", + "2.x\/itop-request-mgmt\/dictionaries\/fr.dict.itop-request-mgmt.php", + "2.x\/itop-request-mgmt\/dictionaries\/ru.dict.itop-request-mgmt.php", + "2.x\/itop-request-mgmt\/dictionaries\/cs.dict.itop-request-mgmt.php", + "2.x\/itop-request-mgmt\/dictionaries\/hu.dict.itop-request-mgmt.php", + "2.x\/itop-request-mgmt\/dictionaries\/en.dict.itop-request-mgmt.php", + "2.x\/itop-request-mgmt\/dictionaries\/pl.dict.itop-request-mgmt.php", + "2.x\/itop-request-mgmt\/dictionaries\/sk.dict.itop-request-mgmt.php", + "2.x\/itop-request-mgmt\/dictionaries\/pt_br.dict.itop-request-mgmt.php", + "2.x\/itop-request-mgmt\/dictionaries\/zh_cn.dict.itop-request-mgmt.php", + "2.x\/itop-request-mgmt\/dictionaries\/de.dict.itop-request-mgmt.php", + "2.x\/itop-request-mgmt\/dictionaries\/es_cr.dict.itop-request-mgmt.php", + "2.x\/itop-request-mgmt\/dictionaries\/en_gb.dict.itop-request-mgmt.php", + "2.x\/itop-request-mgmt\/dictionaries\/nl.dict.itop-request-mgmt.php", + "2.x\/itop-request-mgmt\/dictionaries\/ja.dict.itop-request-mgmt.php" + ], + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 1, + "message": "" + }, + "uninstall": { + "flag": 1, + "message": "" + } + }, + "itop-service-mgmt-provider": { + "label": "Service Management for Service Providers", + "category": "business", + "dependencies": [ + "itop-tickets\/2.0.0" + ], + "mandatory": false, + "visible": true, + "installer": "ServiceMgmtProviderInstaller", + "datamodel": [], + "data.struct": [], + "data.sample": [ + "data.sample.organizations.xml", + "data.sample.contracts.xml", + "data.sample.servicefamilies.xml", + "data.sample.services.xml", + "data.sample.serviceelements.xml", + "data.sample.sla.xml", + "data.sample.slt.xml", + "data.sample.sltsla.xml", + "data.sample.contractservice.xml", + "data.sample.deliverymodelcontact.xml" + ], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-service-mgmt-provider\/module.itop-service-mgmt-provider.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-service-mgmt-provider", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-service-mgmt-provider\/module.itop-service-mgmt-provider.php", + "dictionary": [ + "2.x\/itop-service-mgmt-provider\/dictionaries\/zh_cn.dict.itop-service-mgmt-provider.php", + "2.x\/itop-service-mgmt-provider\/dictionaries\/tr.dict.itop-service-mgmt-provider.php", + "2.x\/itop-service-mgmt-provider\/dictionaries\/sk.dict.itop-service-mgmt-provider.php", + "2.x\/itop-service-mgmt-provider\/dictionaries\/de.dict.itop-service-mgmt-provider.php", + "2.x\/itop-service-mgmt-provider\/dictionaries\/ja.dict.itop-service-mgmt-provider.php", + "2.x\/itop-service-mgmt-provider\/dictionaries\/ru.dict.itop-service-mgmt-provider.php", + "2.x\/itop-service-mgmt-provider\/dictionaries\/pl.dict.itop-service-mgmt-provider.php", + "2.x\/itop-service-mgmt-provider\/dictionaries\/fr.dict.itop-service-mgmt-provider.php", + "2.x\/itop-service-mgmt-provider\/dictionaries\/hu.dict.itop-service-mgmt-provider.php", + "2.x\/itop-service-mgmt-provider\/dictionaries\/en.dict.itop-service-mgmt-provider.php", + "2.x\/itop-service-mgmt-provider\/dictionaries\/it.dict.itop-service-mgmt-provider.php", + "2.x\/itop-service-mgmt-provider\/dictionaries\/cs.dict.itop-service-mgmt-provider.php", + "2.x\/itop-service-mgmt-provider\/dictionaries\/es_cr.dict.itop-service-mgmt-provider.php", + "2.x\/itop-service-mgmt-provider\/dictionaries\/pt_br.dict.itop-service-mgmt-provider.php", + "2.x\/itop-service-mgmt-provider\/dictionaries\/da.dict.itop-service-mgmt-provider.php", + "2.x\/itop-service-mgmt-provider\/dictionaries\/en_gb.dict.itop-service-mgmt-provider.php", + "2.x\/itop-service-mgmt-provider\/dictionaries\/nl.dict.itop-service-mgmt-provider.php" + ], + "installed_version": "", + "available_version": "3.3.0", + "install": { + "flag": 1, + "message": "" + } + }, + "itop-service-mgmt": { + "label": "Service Management", + "category": "business", + "dependencies": [ + "itop-tickets\/2.0.0" + ], + "mandatory": false, + "visible": true, + "installer": "ServiceMgmtInstaller", + "datamodel": [], + "data.struct": [], + "data.sample": [ + "data.sample.organizations.xml", + "data.sample.contracts.xml", + "data.sample.servicefamilies.xml", + "data.sample.services.xml", + "data.sample.serviceelements.xml", + "data.sample.sla.xml", + "data.sample.slt.xml", + "data.sample.sltsla.xml", + "data.sample.contractservice.xml", + "data.sample.deliverymodelcontact.xml" + ], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-service-mgmt\/module.itop-service-mgmt.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-service-mgmt", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-service-mgmt\/module.itop-service-mgmt.php", + "dictionary": [ + "2.x\/itop-service-mgmt\/dictionaries\/en_gb.dict.itop-service-mgmt.php", + "2.x\/itop-service-mgmt\/dictionaries\/hu.dict.itop-service-mgmt.php", + "2.x\/itop-service-mgmt\/dictionaries\/es_cr.dict.itop-service-mgmt.php", + "2.x\/itop-service-mgmt\/dictionaries\/nl.dict.itop-service-mgmt.php", + "2.x\/itop-service-mgmt\/dictionaries\/sk.dict.itop-service-mgmt.php", + "2.x\/itop-service-mgmt\/dictionaries\/it.dict.itop-service-mgmt.php", + "2.x\/itop-service-mgmt\/dictionaries\/da.dict.itop-service-mgmt.php", + "2.x\/itop-service-mgmt\/dictionaries\/zh_cn.dict.itop-service-mgmt.php", + "2.x\/itop-service-mgmt\/dictionaries\/pl.dict.itop-service-mgmt.php", + "2.x\/itop-service-mgmt\/dictionaries\/tr.dict.itop-service-mgmt.php", + "2.x\/itop-service-mgmt\/dictionaries\/en.dict.itop-service-mgmt.php", + "2.x\/itop-service-mgmt\/dictionaries\/cs.dict.itop-service-mgmt.php", + "2.x\/itop-service-mgmt\/dictionaries\/de.dict.itop-service-mgmt.php", + "2.x\/itop-service-mgmt\/dictionaries\/ja.dict.itop-service-mgmt.php", + "2.x\/itop-service-mgmt\/dictionaries\/ru.dict.itop-service-mgmt.php", + "2.x\/itop-service-mgmt\/dictionaries\/pt_br.dict.itop-service-mgmt.php", + "2.x\/itop-service-mgmt\/dictionaries\/fr.dict.itop-service-mgmt.php" + ], + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 1, + "message": "" + }, + "uninstall": { + "flag": 1, + "message": "" + } + }, + "itop-storage-mgmt": { + "label": "Advanced Storage Management", + "category": "business", + "dependencies": [ + "itop-config-mgmt\/2.4.0" + ], + "mandatory": false, + "visible": true, + "installer": "StorageMgmtInstaller", + "datamodel": [], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-storage-mgmt\/module.itop-storage-mgmt.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-storage-mgmt", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-storage-mgmt\/module.itop-storage-mgmt.php", + "dictionary": [ + "2.x\/itop-storage-mgmt\/dictionaries\/en.dict.itop-storage-mgmt.php", + "2.x\/itop-storage-mgmt\/dictionaries\/cs.dict.itop-storage-mgmt.php", + "2.x\/itop-storage-mgmt\/dictionaries\/ja.dict.itop-storage-mgmt.php", + "2.x\/itop-storage-mgmt\/dictionaries\/da.dict.itop-storage-mgmt.php", + "2.x\/itop-storage-mgmt\/dictionaries\/pt_br.dict.itop-storage-mgmt.php", + "2.x\/itop-storage-mgmt\/dictionaries\/it.dict.itop-storage-mgmt.php", + "2.x\/itop-storage-mgmt\/dictionaries\/nl.dict.itop-storage-mgmt.php", + "2.x\/itop-storage-mgmt\/dictionaries\/fr.dict.itop-storage-mgmt.php", + "2.x\/itop-storage-mgmt\/dictionaries\/tr.dict.itop-storage-mgmt.php", + "2.x\/itop-storage-mgmt\/dictionaries\/es_cr.dict.itop-storage-mgmt.php", + "2.x\/itop-storage-mgmt\/dictionaries\/sk.dict.itop-storage-mgmt.php", + "2.x\/itop-storage-mgmt\/dictionaries\/zh_cn.dict.itop-storage-mgmt.php", + "2.x\/itop-storage-mgmt\/dictionaries\/en_gb.dict.itop-storage-mgmt.php", + "2.x\/itop-storage-mgmt\/dictionaries\/de.dict.itop-storage-mgmt.php", + "2.x\/itop-storage-mgmt\/dictionaries\/hu.dict.itop-storage-mgmt.php", + "2.x\/itop-storage-mgmt\/dictionaries\/pl.dict.itop-storage-mgmt.php", + "2.x\/itop-storage-mgmt\/dictionaries\/ru.dict.itop-storage-mgmt.php" + ], + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 1, + "message": "" + }, + "uninstall": { + "flag": 1, + "message": "" + } + }, + "itop-virtualization-mgmt": { + "label": "Virtualization Management", + "category": "business", + "dependencies": [ + "itop-config-mgmt\/2.4.0" + ], + "mandatory": false, + "visible": true, + "datamodel": [], + "webservice": [], + "data.struct": [], + "data.sample": [ + "data.sample.farm.xml", + "data.sample.hypervisor.xml", + "data.sample.vm.xml", + "data.sample.dbserver.xml", + "data.sample.dbschema.xml", + "data.sample.webserver.xml", + "data.sample.webapp.xml", + "data.sample.applicationsolutionci.xml" + ], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-virtualization-mgmt\/module.itop-virtualization-mgmt.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-virtualization-mgmt", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-virtualization-mgmt\/module.itop-virtualization-mgmt.php", + "dictionary": [ + "2.x\/itop-virtualization-mgmt\/dictionaries\/de.dict.itop-virtualization-mgmt.php", + "2.x\/itop-virtualization-mgmt\/dictionaries\/en_gb.dict.itop-virtualization-mgmt.php", + "2.x\/itop-virtualization-mgmt\/dictionaries\/nl.dict.itop-virtualization-mgmt.php", + "2.x\/itop-virtualization-mgmt\/dictionaries\/ja.dict.itop-virtualization-mgmt.php", + "2.x\/itop-virtualization-mgmt\/dictionaries\/zh_cn.dict.itop-virtualization-mgmt.php", + "2.x\/itop-virtualization-mgmt\/dictionaries\/ru.dict.itop-virtualization-mgmt.php", + "2.x\/itop-virtualization-mgmt\/dictionaries\/sk.dict.itop-virtualization-mgmt.php", + "2.x\/itop-virtualization-mgmt\/dictionaries\/tr.dict.itop-virtualization-mgmt.php", + "2.x\/itop-virtualization-mgmt\/dictionaries\/fr.dict.itop-virtualization-mgmt.php", + "2.x\/itop-virtualization-mgmt\/dictionaries\/cs.dict.itop-virtualization-mgmt.php", + "2.x\/itop-virtualization-mgmt\/dictionaries\/da.dict.itop-virtualization-mgmt.php", + "2.x\/itop-virtualization-mgmt\/dictionaries\/hu.dict.itop-virtualization-mgmt.php", + "2.x\/itop-virtualization-mgmt\/dictionaries\/es_cr.dict.itop-virtualization-mgmt.php", + "2.x\/itop-virtualization-mgmt\/dictionaries\/en.dict.itop-virtualization-mgmt.php", + "2.x\/itop-virtualization-mgmt\/dictionaries\/pl.dict.itop-virtualization-mgmt.php", + "2.x\/itop-virtualization-mgmt\/dictionaries\/pt_br.dict.itop-virtualization-mgmt.php", + "2.x\/itop-virtualization-mgmt\/dictionaries\/it.dict.itop-virtualization-mgmt.php" + ], + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 1, + "message": "" + }, + "uninstall": { + "flag": 1, + "message": "" + } + }, + "itop-bridge-cmdb-services": { + "label": "Bridge for CMDB and Services", + "category": "business", + "dependencies": [ + "itop-config-mgmt\/2.7.1", + "itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1" + ], + "mandatory": false, + "visible": false, + "auto_select": "SetupInfo::ModuleIsSelected(\"itop-config-mgmt\") && (SetupInfo::ModuleIsSelected(\"itop-service-mgmt\") || SetupInfo::ModuleIsSelected(\"itop-service-mgmt-provider\")) ", + "datamodel": [], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-cmdb-services\/module.itop-bridge-cmdb-services.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-cmdb-services", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-cmdb-services\/module.itop-bridge-cmdb-services.php", + "dictionary": [ + "2.x\/itop-bridge-cmdb-services\/dictionaries\/es_cr.dict.itop-bridge-cmdb-services.php", + "2.x\/itop-bridge-cmdb-services\/dictionaries\/cs.dict.itop-bridge-cmdb-services.php", + "2.x\/itop-bridge-cmdb-services\/dictionaries\/ja.dict.itop-bridge-cmdb-services.php", + "2.x\/itop-bridge-cmdb-services\/dictionaries\/hu.dict.itop-bridge-cmdb-services.php", + "2.x\/itop-bridge-cmdb-services\/dictionaries\/it.dict.itop-bridge-cmdb-services.php", + "2.x\/itop-bridge-cmdb-services\/dictionaries\/fr.dict.itop-bridge-cmdb-services.php", + "2.x\/itop-bridge-cmdb-services\/dictionaries\/pl.dict.itop-bridge-cmdb-services.php", + "2.x\/itop-bridge-cmdb-services\/dictionaries\/pt_br.dict.itop-bridge-cmdb-services.php", + "2.x\/itop-bridge-cmdb-services\/dictionaries\/nl.dict.itop-bridge-cmdb-services.php", + "2.x\/itop-bridge-cmdb-services\/dictionaries\/tr.dict.itop-bridge-cmdb-services.php", + "2.x\/itop-bridge-cmdb-services\/dictionaries\/da.dict.itop-bridge-cmdb-services.php", + "2.x\/itop-bridge-cmdb-services\/dictionaries\/ru.dict.itop-bridge-cmdb-services.php", + "2.x\/itop-bridge-cmdb-services\/dictionaries\/de.dict.itop-bridge-cmdb-services.php", + "2.x\/itop-bridge-cmdb-services\/dictionaries\/sk.dict.itop-bridge-cmdb-services.php", + "2.x\/itop-bridge-cmdb-services\/dictionaries\/zh_cn.dict.itop-bridge-cmdb-services.php", + "2.x\/itop-bridge-cmdb-services\/dictionaries\/en.dict.itop-bridge-cmdb-services.php", + "2.x\/itop-bridge-cmdb-services\/dictionaries\/en_gb.dict.itop-bridge-cmdb-services.php" + ], + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 1, + "message": "" + }, + "uninstall": { + "flag": 1, + "message": "" + } + }, + "itop-bridge-cmdb-ticket": { + "label": "Bridge for CMDB and Ticket", + "category": "business", + "dependencies": [ + "itop-config-mgmt\/2.7.1", + "itop-tickets\/2.7.0" + ], + "mandatory": false, + "visible": false, + "auto_select": "SetupInfo::ModuleIsSelected(\"itop-config-mgmt\") && SetupInfo::ModuleIsSelected(\"itop-tickets\") ", + "datamodel": [], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-cmdb-ticket\/module.itop-bridge-cmdb-ticket.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-cmdb-ticket", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-cmdb-ticket\/module.itop-bridge-cmdb-ticket.php", + "dictionary": [ + "2.x\/itop-bridge-cmdb-ticket\/dictionaries\/it.dict.itop-bridge-cmdb-ticket.php", + "2.x\/itop-bridge-cmdb-ticket\/dictionaries\/ru.dict.itop-bridge-cmdb-ticket.php", + "2.x\/itop-bridge-cmdb-ticket\/dictionaries\/pt_br.dict.itop-bridge-cmdb-ticket.php", + "2.x\/itop-bridge-cmdb-ticket\/dictionaries\/zh_cn.dict.itop-bridge-cmdb-ticket.php", + "2.x\/itop-bridge-cmdb-ticket\/dictionaries\/en.dict.itop-bridge-cmdb-ticket.php", + "2.x\/itop-bridge-cmdb-ticket\/dictionaries\/ja.dict.itop-bridge-cmdb-ticket.php", + "2.x\/itop-bridge-cmdb-ticket\/dictionaries\/en_gb.dict.itop-bridge-cmdb-ticket.php", + "2.x\/itop-bridge-cmdb-ticket\/dictionaries\/hu.dict.itop-bridge-cmdb-ticket.php", + "2.x\/itop-bridge-cmdb-ticket\/dictionaries\/de.dict.itop-bridge-cmdb-ticket.php", + "2.x\/itop-bridge-cmdb-ticket\/dictionaries\/es_cr.dict.itop-bridge-cmdb-ticket.php", + "2.x\/itop-bridge-cmdb-ticket\/dictionaries\/tr.dict.itop-bridge-cmdb-ticket.php", + "2.x\/itop-bridge-cmdb-ticket\/dictionaries\/pl.dict.itop-bridge-cmdb-ticket.php", + "2.x\/itop-bridge-cmdb-ticket\/dictionaries\/fr.dict.itop-bridge-cmdb-ticket.php", + "2.x\/itop-bridge-cmdb-ticket\/dictionaries\/cs.dict.itop-bridge-cmdb-ticket.php", + "2.x\/itop-bridge-cmdb-ticket\/dictionaries\/da.dict.itop-bridge-cmdb-ticket.php", + "2.x\/itop-bridge-cmdb-ticket\/dictionaries\/nl.dict.itop-bridge-cmdb-ticket.php", + "2.x\/itop-bridge-cmdb-ticket\/dictionaries\/sk.dict.itop-bridge-cmdb-ticket.php" + ], + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 1, + "message": "" + }, + "uninstall": { + "flag": 1, + "message": "" + } + }, + "itop-bridge-datacenter-mgmt-services": { + "label": "Bridge for CMDB Virtualization objects and Services", + "category": "business", + "dependencies": [ + "itop-config-mgmt\/2.7.1", + "itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1", + "itop-datacenter-mgmt\/3.1.0" + ], + "mandatory": false, + "visible": false, + "auto_select": "SetupInfo::ModuleIsSelected(\"itop-datacenter-mgmt\") && (SetupInfo::ModuleIsSelected(\"itop-service-mgmt\") || SetupInfo::ModuleIsSelected(\"itop-service-mgmt-provider\")) ", + "datamodel": [], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-datacenter-mgmt-services\/module.itop-bridge-datacenter-mgmt-services.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-datacenter-mgmt-services", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-datacenter-mgmt-services\/module.itop-bridge-datacenter-mgmt-services.php", + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 1, + "message": "" + }, + "uninstall": { + "flag": 1, + "message": "" + } + }, + "itop-bridge-endusers-devices-services": { + "label": "Bridge for CMDB endusers objects and Services", + "category": "business", + "dependencies": [ + "itop-config-mgmt\/2.7.1", + "itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1", + "itop-endusers-devices\/3.1.0" + ], + "mandatory": false, + "visible": false, + "auto_select": "SetupInfo::ModuleIsSelected(\"itop-endusers-devices\") && (SetupInfo::ModuleIsSelected(\"itop-service-mgmt\") || SetupInfo::ModuleIsSelected(\"itop-service-mgmt-provider\")) ", + "datamodel": [], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-endusers-devices-services\/module.itop-bridge-endusers-devices-services.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-endusers-devices-services", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-endusers-devices-services\/module.itop-bridge-endusers-devices-services.php", + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 1, + "message": "" + }, + "uninstall": { + "flag": 1, + "message": "" + } + }, + "itop-bridge-storage-mgmt-services": { + "label": "Bridge for CMDB Virtualization objects and Services", + "category": "business", + "dependencies": [ + "itop-config-mgmt\/2.7.1", + "itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1", + "itop-storage-mgmt\/3.1.0" + ], + "mandatory": false, + "visible": false, + "auto_select": "SetupInfo::ModuleIsSelected(\"itop-storage-mgmt\") && (SetupInfo::ModuleIsSelected(\"itop-service-mgmt\") || SetupInfo::ModuleIsSelected(\"itop-service-mgmt-provider\")) ", + "datamodel": [], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-storage-mgmt-services\/module.itop-bridge-storage-mgmt-services.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-storage-mgmt-services", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-storage-mgmt-services\/module.itop-bridge-storage-mgmt-services.php", + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 1, + "message": "" + }, + "uninstall": { + "flag": 1, + "message": "" + } + }, + "itop-bridge-virtualization-mgmt-services": { + "label": "Bridge for CMDB Virtualization objects and Services", + "category": "business", + "dependencies": [ + "itop-config-mgmt\/2.7.1", + "itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1", + "itop-virtualization-mgmt\/3.1.0" + ], + "mandatory": false, + "visible": false, + "auto_select": "SetupInfo::ModuleIsSelected(\"itop-virtualization-mgmt\") && (SetupInfo::ModuleIsSelected(\"itop-service-mgmt\") || SetupInfo::ModuleIsSelected(\"itop-service-mgmt-provider\")) ", + "datamodel": [], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-virtualization-mgmt-services\/module.itop-bridge-virtualization-mgmt-services.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-virtualization-mgmt-services", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-virtualization-mgmt-services\/module.itop-bridge-virtualization-mgmt-services.php", + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 1, + "message": "" + }, + "uninstall": { + "flag": 1, + "message": "" + } + }, + "itop-bridge-virtualization-storage": { + "label": "Links between virtualization and storage", + "category": "business", + "dependencies": [ + "itop-storage-mgmt\/2.2.0", + "itop-virtualization-mgmt\/2.2.0" + ], + "mandatory": false, + "visible": false, + "auto_select": "SetupInfo::ModuleIsSelected(\"itop-storage-mgmt\") && SetupInfo::ModuleIsSelected(\"itop-virtualization-mgmt\")", + "datamodel": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-virtualization-storage\/module.itop-bridge-virtualization-storage.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-virtualization-storage", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-virtualization-storage\/module.itop-bridge-virtualization-storage.php", + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 1, + "message": "" + }, + "uninstall": { + "flag": 1, + "message": "" + } + }, + "itop-change-mgmt-itil": { + "label": "Change Management ITIL", + "category": "business", + "dependencies": [ + "itop-config-mgmt\/2.2.0", + "itop-tickets\/2.0.0" + ], + "mandatory": false, + "visible": true, + "datamodel": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-change-mgmt-itil\/module.itop-change-mgmt-itil.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-change-mgmt-itil", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-change-mgmt-itil\/module.itop-change-mgmt-itil.php", + "dictionary": [ + "2.x\/itop-change-mgmt-itil\/dictionaries\/hu.dict.itop-change-mgmt-itil.php", + "2.x\/itop-change-mgmt-itil\/dictionaries\/tr.dict.itop-change-mgmt-itil.php", + "2.x\/itop-change-mgmt-itil\/dictionaries\/fr.dict.itop-change-mgmt-itil.php", + "2.x\/itop-change-mgmt-itil\/dictionaries\/en.dict.itop-change-mgmt-itil.php", + "2.x\/itop-change-mgmt-itil\/dictionaries\/cs.dict.itop-change-mgmt-itil.php", + "2.x\/itop-change-mgmt-itil\/dictionaries\/da.dict.itop-change-mgmt-itil.php", + "2.x\/itop-change-mgmt-itil\/dictionaries\/sk.dict.itop-change-mgmt-itil.php", + "2.x\/itop-change-mgmt-itil\/dictionaries\/en_gb.dict.itop-change-mgmt-itil.php", + "2.x\/itop-change-mgmt-itil\/dictionaries\/nl.dict.itop-change-mgmt-itil.php", + "2.x\/itop-change-mgmt-itil\/dictionaries\/ja.dict.itop-change-mgmt-itil.php", + "2.x\/itop-change-mgmt-itil\/dictionaries\/es_cr.dict.itop-change-mgmt-itil.php", + "2.x\/itop-change-mgmt-itil\/dictionaries\/zh_cn.dict.itop-change-mgmt-itil.php", + "2.x\/itop-change-mgmt-itil\/dictionaries\/de.dict.itop-change-mgmt-itil.php", + "2.x\/itop-change-mgmt-itil\/dictionaries\/it.dict.itop-change-mgmt-itil.php", + "2.x\/itop-change-mgmt-itil\/dictionaries\/ru.dict.itop-change-mgmt-itil.php", + "2.x\/itop-change-mgmt-itil\/dictionaries\/pl.dict.itop-change-mgmt-itil.php", + "2.x\/itop-change-mgmt-itil\/dictionaries\/pt_br.dict.itop-change-mgmt-itil.php" + ], + "installed_version": "", + "available_version": "3.3.0", + "install": { + "flag": 1, + "message": "" + } + }, + "itop-change-mgmt": { + "label": "Change Management", + "category": "business", + "dependencies": [ + "itop-config-mgmt\/2.2.0", + "itop-tickets\/2.0.0" + ], + "mandatory": false, + "visible": true, + "installer": "ChangeManagementInstaller", + "datamodel": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-change-mgmt\/module.itop-change-mgmt.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-change-mgmt", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-change-mgmt\/module.itop-change-mgmt.php", + "dictionary": [ + "2.x\/itop-change-mgmt\/dictionaries\/zh_cn.dict.itop-change-mgmt.php", + "2.x\/itop-change-mgmt\/dictionaries\/en.dict.itop-change-mgmt.php", + "2.x\/itop-change-mgmt\/dictionaries\/tr.dict.itop-change-mgmt.php", + "2.x\/itop-change-mgmt\/dictionaries\/it.dict.itop-change-mgmt.php", + "2.x\/itop-change-mgmt\/dictionaries\/cs.dict.itop-change-mgmt.php", + "2.x\/itop-change-mgmt\/dictionaries\/hu.dict.itop-change-mgmt.php", + "2.x\/itop-change-mgmt\/dictionaries\/pl.dict.itop-change-mgmt.php", + "2.x\/itop-change-mgmt\/dictionaries\/en_gb.dict.itop-change-mgmt.php", + "2.x\/itop-change-mgmt\/dictionaries\/ja.dict.itop-change-mgmt.php", + "2.x\/itop-change-mgmt\/dictionaries\/da.dict.itop-change-mgmt.php", + "2.x\/itop-change-mgmt\/dictionaries\/es_cr.dict.itop-change-mgmt.php", + "2.x\/itop-change-mgmt\/dictionaries\/de.dict.itop-change-mgmt.php", + "2.x\/itop-change-mgmt\/dictionaries\/nl.dict.itop-change-mgmt.php", + "2.x\/itop-change-mgmt\/dictionaries\/sk.dict.itop-change-mgmt.php", + "2.x\/itop-change-mgmt\/dictionaries\/ru.dict.itop-change-mgmt.php", + "2.x\/itop-change-mgmt\/dictionaries\/pt_br.dict.itop-change-mgmt.php", + "2.x\/itop-change-mgmt\/dictionaries\/fr.dict.itop-change-mgmt.php" + ], + "installed_version": "3.3.0", + "available_version": "3.3.0", + "install": { + "flag": 1, + "message": "" + }, + "uninstall": { + "flag": 1, + "message": "" + } + }, + "itop-full-itil": { + "label": "Bridge - Request management ITIL + Incident management ITIL", + "category": "business", + "dependencies": [ + "itop-request-mgmt-itil\/2.3.0", + "itop-incident-mgmt-itil\/2.3.0" + ], + "mandatory": false, + "visible": false, + "auto_select": "SetupInfo::ModuleIsSelected(\"itop-request-mgmt-itil\") && SetupInfo::ModuleIsSelected(\"itop-incident-mgmt-itil\")", + "datamodel": [], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-full-itil\/module.itop-full-itil.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-full-itil", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-full-itil\/module.itop-full-itil.php", + "installed_version": "", + "available_version": "3.3.0", + "install": { + "flag": 1, + "message": "" + } + } +} \ No newline at end of file diff --git a/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/available_modules.json b/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/available_modules.json new file mode 100644 index 0000000000..efd6268d21 --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/available_modules.json @@ -0,0 +1,1822 @@ +{ + "authent-cas\/3.3.0": { + "label": "CAS SSO", + "category": "authentication", + "dependencies": [], + "mandatory": true, + "visible": true, + "datamodel": [ + "vendor\/autoload.php", + "src\/CASLoginExtension.php" + ], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": { + "cas_debug": false, + "cas_host": "", + "cas_port": "", + "cas_context": "", + "cas_version": "", + "service_base_url": "" + }, + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/authent-cas\/module.authent-cas.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/authent-cas", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/authent-cas\/module.authent-cas.php", + "dictionary": [ + "2.x\/authent-cas\/dictionaries\/de.dict.authent-cas.php", + "2.x\/authent-cas\/dictionaries\/en_gb.dict.authent-cas.php", + "2.x\/authent-cas\/dictionaries\/cs.dict.authent-cas.php", + "2.x\/authent-cas\/dictionaries\/pl.dict.authent-cas.php", + "2.x\/authent-cas\/dictionaries\/nl.dict.authent-cas.php", + "2.x\/authent-cas\/dictionaries\/da.dict.authent-cas.php", + "2.x\/authent-cas\/dictionaries\/tr.dict.authent-cas.php", + "2.x\/authent-cas\/dictionaries\/ru.dict.authent-cas.php", + "2.x\/authent-cas\/dictionaries\/ja.dict.authent-cas.php", + "2.x\/authent-cas\/dictionaries\/es_cr.dict.authent-cas.php", + "2.x\/authent-cas\/dictionaries\/it.dict.authent-cas.php", + "2.x\/authent-cas\/dictionaries\/pt_br.dict.authent-cas.php", + "2.x\/authent-cas\/dictionaries\/sk.dict.authent-cas.php", + "2.x\/authent-cas\/dictionaries\/hu.dict.authent-cas.php", + "2.x\/authent-cas\/dictionaries\/zh_cn.dict.authent-cas.php", + "2.x\/authent-cas\/dictionaries\/en.dict.authent-cas.php", + "2.x\/authent-cas\/dictionaries\/fr.dict.authent-cas.php" + ] + }, + "authent-external\/3.3.0": { + "label": "External user authentication", + "category": "authentication", + "dependencies": [], + "mandatory": false, + "visible": true, + "datamodel": [ + "model.authent-external.php" + ], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/authent-external\/module.authent-external.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/authent-external", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/authent-external\/module.authent-external.php", + "dictionary": [ + "2.x\/authent-external\/dictionaries\/fr.dict.authent-external.php", + "2.x\/authent-external\/dictionaries\/de.dict.authent-external.php", + "2.x\/authent-external\/dictionaries\/zh_cn.dict.authent-external.php", + "2.x\/authent-external\/dictionaries\/pl.dict.authent-external.php", + "2.x\/authent-external\/dictionaries\/tr.dict.authent-external.php", + "2.x\/authent-external\/dictionaries\/en_gb.dict.authent-external.php", + "2.x\/authent-external\/dictionaries\/pt_br.dict.authent-external.php", + "2.x\/authent-external\/dictionaries\/da.dict.authent-external.php", + "2.x\/authent-external\/dictionaries\/ru.dict.authent-external.php", + "2.x\/authent-external\/dictionaries\/cs.dict.authent-external.php", + "2.x\/authent-external\/dictionaries\/it.dict.authent-external.php", + "2.x\/authent-external\/dictionaries\/en.dict.authent-external.php", + "2.x\/authent-external\/dictionaries\/hu.dict.authent-external.php", + "2.x\/authent-external\/dictionaries\/sk.dict.authent-external.php", + "2.x\/authent-external\/dictionaries\/ja.dict.authent-external.php", + "2.x\/authent-external\/dictionaries\/nl.dict.authent-external.php", + "2.x\/authent-external\/dictionaries\/es_cr.dict.authent-external.php" + ] + }, + "authent-ldap\/3.3.0": { + "label": "User authentication based on LDAP", + "category": "authentication", + "dependencies": [], + "mandatory": false, + "visible": true, + "installer": "AuthentLDAPInstaller", + "datamodel": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": { + "uri": "ldap:\/\/localhost", + "default_user": "", + "default_pwd": "", + "base_dn": "dc=yourcompany,dc=com", + "user_query": "(&(uid=%1$s)(inetuserstatus=ACTIVE))", + "options": { + "17": 3, + "8": 0 + }, + "start_tls": false, + "debug": false, + "servers": [] + }, + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/authent-ldap\/module.authent-ldap.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/authent-ldap", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/authent-ldap\/module.authent-ldap.php", + "dictionary": [ + "2.x\/authent-ldap\/dictionaries\/en.dict.authent-ldap.php", + "2.x\/authent-ldap\/dictionaries\/pl.dict.authent-ldap.php", + "2.x\/authent-ldap\/dictionaries\/ru.dict.authent-ldap.php", + "2.x\/authent-ldap\/dictionaries\/cs.dict.authent-ldap.php", + "2.x\/authent-ldap\/dictionaries\/es_cr.dict.authent-ldap.php", + "2.x\/authent-ldap\/dictionaries\/zh_cn.dict.authent-ldap.php", + "2.x\/authent-ldap\/dictionaries\/pt_br.dict.authent-ldap.php", + "2.x\/authent-ldap\/dictionaries\/it.dict.authent-ldap.php", + "2.x\/authent-ldap\/dictionaries\/tr.dict.authent-ldap.php", + "2.x\/authent-ldap\/dictionaries\/fr.dict.authent-ldap.php", + "2.x\/authent-ldap\/dictionaries\/en_gb.dict.authent-ldap.php", + "2.x\/authent-ldap\/dictionaries\/de.dict.authent-ldap.php", + "2.x\/authent-ldap\/dictionaries\/da.dict.authent-ldap.php", + "2.x\/authent-ldap\/dictionaries\/nl.dict.authent-ldap.php", + "2.x\/authent-ldap\/dictionaries\/hu.dict.authent-ldap.php", + "2.x\/authent-ldap\/dictionaries\/sk.dict.authent-ldap.php", + "2.x\/authent-ldap\/dictionaries\/ja.dict.authent-ldap.php" + ] + }, + "authent-local\/3.3.0": { + "label": "User authentication based on the local DB", + "category": "authentication", + "dependencies": [], + "mandatory": true, + "visible": true, + "datamodel": [ + "model.authent-local.php" + ], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/authent-local\/module.authent-local.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/authent-local", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/authent-local\/module.authent-local.php", + "dictionary": [ + "2.x\/authent-local\/dictionaries\/en_gb.dict.authent-local.php", + "2.x\/authent-local\/dictionaries\/hu.dict.authent-local.php", + "2.x\/authent-local\/dictionaries\/de.dict.authent-local.php", + "2.x\/authent-local\/dictionaries\/ja.dict.authent-local.php", + "2.x\/authent-local\/dictionaries\/fr.dict.authent-local.php", + "2.x\/authent-local\/dictionaries\/es_cr.dict.authent-local.php", + "2.x\/authent-local\/dictionaries\/it.dict.authent-local.php", + "2.x\/authent-local\/dictionaries\/tr.dict.authent-local.php", + "2.x\/authent-local\/dictionaries\/da.dict.authent-local.php", + "2.x\/authent-local\/dictionaries\/sk.dict.authent-local.php", + "2.x\/authent-local\/dictionaries\/pl.dict.authent-local.php", + "2.x\/authent-local\/dictionaries\/ru.dict.authent-local.php", + "2.x\/authent-local\/dictionaries\/nl.dict.authent-local.php", + "2.x\/authent-local\/dictionaries\/zh_cn.dict.authent-local.php", + "2.x\/authent-local\/dictionaries\/cs.dict.authent-local.php", + "2.x\/authent-local\/dictionaries\/en.dict.authent-local.php", + "2.x\/authent-local\/dictionaries\/pt_br.dict.authent-local.php" + ] + }, + "combodo-backoffice-darkmoon-theme\/3.3.0": { + "label": "Backoffice: Darkmoon theme", + "category": "business", + "dependencies": [], + "mandatory": true, + "visible": false, + "datamodel": [], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/combodo-backoffice-darkmoon-theme\/module.combodo-backoffice-darkmoon-theme.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/combodo-backoffice-darkmoon-theme", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/combodo-backoffice-darkmoon-theme\/module.combodo-backoffice-darkmoon-theme.php", + "dictionary": [ + "2.x\/combodo-backoffice-darkmoon-theme\/dictionaries\/es_cr.dict.combodo-backoffice-darkmoon-theme.php", + "2.x\/combodo-backoffice-darkmoon-theme\/dictionaries\/tr.dict.combodo-backoffice-darkmoon-theme.php", + "2.x\/combodo-backoffice-darkmoon-theme\/dictionaries\/sk.dict.combodo-backoffice-darkmoon-theme.php", + "2.x\/combodo-backoffice-darkmoon-theme\/dictionaries\/pt_br.dict.combodo-backoffice-darkmoon-theme.php", + "2.x\/combodo-backoffice-darkmoon-theme\/dictionaries\/it.dict.combodo-backoffice-darkmoon-theme.php", + "2.x\/combodo-backoffice-darkmoon-theme\/dictionaries\/en_gb.dict.combodo-backoffice-darkmoon-theme.php", + "2.x\/combodo-backoffice-darkmoon-theme\/dictionaries\/da.dict.combodo-backoffice-darkmoon-theme.php", + "2.x\/combodo-backoffice-darkmoon-theme\/dictionaries\/nl.dict.combodo-backoffice-darkmoon-theme.php", + "2.x\/combodo-backoffice-darkmoon-theme\/dictionaries\/ja.dict.combodo-backoffice-darkmoon-theme.php", + "2.x\/combodo-backoffice-darkmoon-theme\/dictionaries\/hu.dict.combodo-backoffice-darkmoon-theme.php", + "2.x\/combodo-backoffice-darkmoon-theme\/dictionaries\/pl.dict.combodo-backoffice-darkmoon-theme.php", + "2.x\/combodo-backoffice-darkmoon-theme\/dictionaries\/de.dict.combodo-backoffice-darkmoon-theme.php", + "2.x\/combodo-backoffice-darkmoon-theme\/dictionaries\/zh_cn.dict.combodo-backoffice-darkmoon-theme.php", + "2.x\/combodo-backoffice-darkmoon-theme\/dictionaries\/ru.dict.combodo-backoffice-darkmoon-theme.php", + "2.x\/combodo-backoffice-darkmoon-theme\/dictionaries\/fr.dict.combodo-backoffice-darkmoon-theme.php", + "2.x\/combodo-backoffice-darkmoon-theme\/dictionaries\/en.dict.combodo-backoffice-darkmoon-theme.php", + "2.x\/combodo-backoffice-darkmoon-theme\/dictionaries\/cs.dict.combodo-backoffice-darkmoon-theme.php" + ] + }, + "combodo-backoffice-fullmoon-high-contrast-theme\/3.3.0": { + "label": "Backoffice: Fullmoon with high contrast accessibility theme", + "category": "business", + "dependencies": [], + "mandatory": true, + "visible": false, + "datamodel": [], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/combodo-backoffice-fullmoon-high-contrast-theme\/module.combodo-backoffice-fullmoon-high-contrast-theme.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/combodo-backoffice-fullmoon-high-contrast-theme", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/combodo-backoffice-fullmoon-high-contrast-theme\/module.combodo-backoffice-fullmoon-high-contrast-theme.php", + "dictionary": [ + "2.x\/combodo-backoffice-fullmoon-high-contrast-theme\/dictionaries\/es_cr.dict.combodo-backoffice-fullmoon-high-contrast-theme.php", + "2.x\/combodo-backoffice-fullmoon-high-contrast-theme\/dictionaries\/en_gb.dict.combodo-backoffice-fullmoon-high-contrast-theme.php", + "2.x\/combodo-backoffice-fullmoon-high-contrast-theme\/dictionaries\/sk.dict.combodo-backoffice-fullmoon-high-contrast-theme.php", + "2.x\/combodo-backoffice-fullmoon-high-contrast-theme\/dictionaries\/tr.dict.combodo-backoffice-fullmoon-high-contrast-theme.php", + "2.x\/combodo-backoffice-fullmoon-high-contrast-theme\/dictionaries\/en.dict.combodo-backoffice-fullmoon-high-contrast-theme.php", + "2.x\/combodo-backoffice-fullmoon-high-contrast-theme\/dictionaries\/pt_br.dict.combodo-backoffice-fullmoon-high-contrast-theme.php", + "2.x\/combodo-backoffice-fullmoon-high-contrast-theme\/dictionaries\/cs.dict.combodo-backoffice-fullmoon-high-contrast-theme.php", + "2.x\/combodo-backoffice-fullmoon-high-contrast-theme\/dictionaries\/fr.dict.combodo-backoffice-fullmoon-high-contrast-theme.php", + "2.x\/combodo-backoffice-fullmoon-high-contrast-theme\/dictionaries\/hu.dict.combodo-backoffice-fullmoon-high-contrast-theme.php", + "2.x\/combodo-backoffice-fullmoon-high-contrast-theme\/dictionaries\/it.dict.combodo-backoffice-fullmoon-high-contrast-theme.php", + "2.x\/combodo-backoffice-fullmoon-high-contrast-theme\/dictionaries\/ru.dict.combodo-backoffice-fullmoon-high-contrast-theme.php", + "2.x\/combodo-backoffice-fullmoon-high-contrast-theme\/dictionaries\/pl.dict.combodo-backoffice-fullmoon-high-contrast-theme.php", + "2.x\/combodo-backoffice-fullmoon-high-contrast-theme\/dictionaries\/da.dict.combodo-backoffice-fullmoon-high-contrast-theme.php", + "2.x\/combodo-backoffice-fullmoon-high-contrast-theme\/dictionaries\/ja.dict.combodo-backoffice-fullmoon-high-contrast-theme.php", + "2.x\/combodo-backoffice-fullmoon-high-contrast-theme\/dictionaries\/zh_cn.dict.combodo-backoffice-fullmoon-high-contrast-theme.php", + "2.x\/combodo-backoffice-fullmoon-high-contrast-theme\/dictionaries\/nl.dict.combodo-backoffice-fullmoon-high-contrast-theme.php", + "2.x\/combodo-backoffice-fullmoon-high-contrast-theme\/dictionaries\/de.dict.combodo-backoffice-fullmoon-high-contrast-theme.php" + ] + }, + "combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/3.3.0": { + "label": "Backoffice: Fullmoon with protonopia & deuteranopia accessibility theme", + "category": "business", + "dependencies": [], + "mandatory": true, + "visible": false, + "datamodel": [], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/module.combodo-backoffice-fullmoon-protanopia-deuteranopia-theme.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/module.combodo-backoffice-fullmoon-protanopia-deuteranopia-theme.php", + "dictionary": [ + "2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/dictionaries\/pl.dict.combodo-backoffice-fullmoon-protanopia-deuteranopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/dictionaries\/ja.dict.combodo-backoffice-fullmoon-protanopia-deuteranopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/dictionaries\/da.dict.combodo-backoffice-fullmoon-protanopia-deuteranopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/dictionaries\/de.dict.combodo-backoffice-fullmoon-protanopia-deuteranopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/dictionaries\/cs.dict.combodo-backoffice-fullmoon-protanopia-deuteranopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/dictionaries\/es_cr.dict.combodo-backoffice-fullmoon-protanopia-deuteranopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/dictionaries\/zh_cn.dict.combodo-backoffice-fullmoon-protanopia-deuteranopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/dictionaries\/sk.dict.combodo-backoffice-fullmoon-protanopia-deuteranopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/dictionaries\/nl.dict.combodo-backoffice-fullmoon-protanopia-deuteranopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/dictionaries\/tr.dict.combodo-backoffice-fullmoon-protanopia-deuteranopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/dictionaries\/pt_br.dict.combodo-backoffice-fullmoon-protanopia-deuteranopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/dictionaries\/it.dict.combodo-backoffice-fullmoon-protanopia-deuteranopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/dictionaries\/fr.dict.combodo-backoffice-fullmoon-protanopia-deuteranopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/dictionaries\/ru.dict.combodo-backoffice-fullmoon-protanopia-deuteranopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/dictionaries\/en_gb.dict.combodo-backoffice-fullmoon-protanopia-deuteranopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/dictionaries\/hu.dict.combodo-backoffice-fullmoon-protanopia-deuteranopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-protanopia-deuteranopia-theme\/dictionaries\/en.dict.combodo-backoffice-fullmoon-protanopia-deuteranopia-theme.php" + ] + }, + "combodo-backoffice-fullmoon-tritanopia-theme\/3.3.0": { + "label": "Backoffice: Fullmoon with tritanopia accessibility theme", + "category": "business", + "dependencies": [], + "mandatory": true, + "visible": false, + "datamodel": [], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/combodo-backoffice-fullmoon-tritanopia-theme\/module.combodo-backoffice-fullmoon-tritanopia-theme.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/combodo-backoffice-fullmoon-tritanopia-theme", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/combodo-backoffice-fullmoon-tritanopia-theme\/module.combodo-backoffice-fullmoon-tritanopia-theme.php", + "dictionary": [ + "2.x\/combodo-backoffice-fullmoon-tritanopia-theme\/dictionaries\/en.dict.combodo-backoffice-fullmoon-tritanopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-tritanopia-theme\/dictionaries\/ru.dict.combodo-backoffice-fullmoon-tritanopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-tritanopia-theme\/dictionaries\/da.dict.combodo-backoffice-fullmoon-tritanopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-tritanopia-theme\/dictionaries\/fr.dict.combodo-backoffice-fullmoon-tritanopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-tritanopia-theme\/dictionaries\/pl.dict.combodo-backoffice-fullmoon-tritanopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-tritanopia-theme\/dictionaries\/it.dict.combodo-backoffice-fullmoon-tritanopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-tritanopia-theme\/dictionaries\/ja.dict.combodo-backoffice-fullmoon-tritanopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-tritanopia-theme\/dictionaries\/hu.dict.combodo-backoffice-fullmoon-tritanopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-tritanopia-theme\/dictionaries\/tr.dict.combodo-backoffice-fullmoon-tritanopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-tritanopia-theme\/dictionaries\/en_gb.dict.combodo-backoffice-fullmoon-tritanopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-tritanopia-theme\/dictionaries\/de.dict.combodo-backoffice-fullmoon-tritanopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-tritanopia-theme\/dictionaries\/nl.dict.combodo-backoffice-fullmoon-tritanopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-tritanopia-theme\/dictionaries\/zh_cn.dict.combodo-backoffice-fullmoon-tritanopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-tritanopia-theme\/dictionaries\/sk.dict.combodo-backoffice-fullmoon-tritanopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-tritanopia-theme\/dictionaries\/pt_br.dict.combodo-backoffice-fullmoon-tritanopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-tritanopia-theme\/dictionaries\/cs.dict.combodo-backoffice-fullmoon-tritanopia-theme.php", + "2.x\/combodo-backoffice-fullmoon-tritanopia-theme\/dictionaries\/es_cr.dict.combodo-backoffice-fullmoon-tritanopia-theme.php" + ] + }, + "itop-attachments\/3.3.0": { + "label": "Tickets Attachments", + "category": "business", + "dependencies": [], + "mandatory": false, + "visible": true, + "installer": "AttachmentInstaller", + "datamodel": [ + "vendor\/autoload.php", + "main.itop-attachments.php", + "src\/Trigger\/TriggerOnAttachmentCreate.php", + "src\/Trigger\/TriggerOnAttachmentDelete.php", + "src\/Trigger\/TriggerOnAttachmentDownload.php", + "renderers.itop-attachments.php" + ], + "webservice": [], + "dictionary": [ + "2.x\/itop-attachments\/dictionaries\/cs.dict.itop-attachments.php", + "2.x\/itop-attachments\/dictionaries\/ja.dict.itop-attachments.php", + "2.x\/itop-attachments\/dictionaries\/es_cr.dict.itop-attachments.php", + "2.x\/itop-attachments\/dictionaries\/ru.dict.itop-attachments.php", + "2.x\/itop-attachments\/dictionaries\/it.dict.itop-attachments.php", + "2.x\/itop-attachments\/dictionaries\/zh_cn.dict.itop-attachments.php", + "2.x\/itop-attachments\/dictionaries\/hu.dict.itop-attachments.php", + "2.x\/itop-attachments\/dictionaries\/da.dict.itop-attachments.php", + "2.x\/itop-attachments\/dictionaries\/en.dict.itop-attachments.php", + "2.x\/itop-attachments\/dictionaries\/sk.dict.itop-attachments.php", + "2.x\/itop-attachments\/dictionaries\/pt_br.dict.itop-attachments.php", + "2.x\/itop-attachments\/dictionaries\/fr.dict.itop-attachments.php", + "2.x\/itop-attachments\/dictionaries\/de.dict.itop-attachments.php", + "2.x\/itop-attachments\/dictionaries\/en_gb.dict.itop-attachments.php", + "2.x\/itop-attachments\/dictionaries\/pl.dict.itop-attachments.php", + "2.x\/itop-attachments\/dictionaries\/tr.dict.itop-attachments.php", + "2.x\/itop-attachments\/dictionaries\/nl.dict.itop-attachments.php" + ], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": { + "allowed_classes": [ + "Ticket" + ], + "position": "relations", + "preview_max_width": 290, + "icon_preview_max_size": 500000 + }, + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-attachments\/module.itop-attachments.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-attachments", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-attachments\/module.itop-attachments.php" + }, + "itop-backup\/3.3.0": { + "label": "Backup utilities", + "category": "Application management", + "dependencies": [], + "mandatory": true, + "visible": false, + "datamodel": [ + "main.itop-backup.php" + ], + "webservice": [], + "dictionary": [ + "en.dict.itop-backup.php", + "fr.dict.itop-backup.php", + "2.x\/itop-backup\/dictionaries\/cs.dict.itop-backup.php", + "2.x\/itop-backup\/dictionaries\/es_cr.dict.itop-backup.php", + "2.x\/itop-backup\/dictionaries\/pl.dict.itop-backup.php", + "2.x\/itop-backup\/dictionaries\/fr.dict.itop-backup.php", + "2.x\/itop-backup\/dictionaries\/de.dict.itop-backup.php", + "2.x\/itop-backup\/dictionaries\/ja.dict.itop-backup.php", + "2.x\/itop-backup\/dictionaries\/en.dict.itop-backup.php", + "2.x\/itop-backup\/dictionaries\/hu.dict.itop-backup.php", + "2.x\/itop-backup\/dictionaries\/nl.dict.itop-backup.php", + "2.x\/itop-backup\/dictionaries\/it.dict.itop-backup.php", + "2.x\/itop-backup\/dictionaries\/sk.dict.itop-backup.php", + "2.x\/itop-backup\/dictionaries\/ru.dict.itop-backup.php", + "2.x\/itop-backup\/dictionaries\/tr.dict.itop-backup.php", + "2.x\/itop-backup\/dictionaries\/pt_br.dict.itop-backup.php", + "2.x\/itop-backup\/dictionaries\/en_gb.dict.itop-backup.php", + "2.x\/itop-backup\/dictionaries\/da.dict.itop-backup.php", + "2.x\/itop-backup\/dictionaries\/zh_cn.dict.itop-backup.php" + ], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": { + "mysql_bindir": "", + "week_days": "monday, tuesday, wednesday, thursday, friday", + "time": "23:30", + "retention_count": 5, + "enabled": true, + "itop_backup_incident": "" + }, + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-backup\/module.itop-backup.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-backup", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-backup\/module.itop-backup.php" + }, + "itop-config\/3.3.0": { + "label": "Configuration editor", + "category": "Application management", + "dependencies": [], + "mandatory": true, + "visible": false, + "datamodel": [ + "src\/Validator\/ConfigNodesVisitor.php", + "src\/Validator\/iTopConfigAstValidator.php", + "src\/Validator\/iTopConfigSyntaxValidator.php", + "src\/Validator\/iTopConfigValidator.php", + "src\/Controller\/ConfigEditorController.php" + ], + "webservice": [], + "dictionary": [ + "en.dict.itop-config.php", + "fr.dict.itop-config.php", + "2.x\/itop-config\/dictionaries\/pl.dict.itop-config.php", + "2.x\/itop-config\/dictionaries\/ru.dict.itop-config.php", + "2.x\/itop-config\/dictionaries\/en.dict.itop-config.php", + "2.x\/itop-config\/dictionaries\/sk.dict.itop-config.php", + "2.x\/itop-config\/dictionaries\/en_gb.dict.itop-config.php", + "2.x\/itop-config\/dictionaries\/cs.dict.itop-config.php", + "2.x\/itop-config\/dictionaries\/de.dict.itop-config.php", + "2.x\/itop-config\/dictionaries\/zh_cn.dict.itop-config.php", + "2.x\/itop-config\/dictionaries\/nl.dict.itop-config.php", + "2.x\/itop-config\/dictionaries\/es_cr.dict.itop-config.php", + "2.x\/itop-config\/dictionaries\/da.dict.itop-config.php", + "2.x\/itop-config\/dictionaries\/ja.dict.itop-config.php", + "2.x\/itop-config\/dictionaries\/pt_br.dict.itop-config.php", + "2.x\/itop-config\/dictionaries\/tr.dict.itop-config.php", + "2.x\/itop-config\/dictionaries\/hu.dict.itop-config.php", + "2.x\/itop-config\/dictionaries\/it.dict.itop-config.php", + "2.x\/itop-config\/dictionaries\/fr.dict.itop-config.php" + ], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-config\/module.itop-config.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-config", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-config\/module.itop-config.php" + }, + "itop-files-information\/3.3.0": { + "label": "iTop files information", + "category": "business", + "dependencies": [], + "mandatory": false, + "visible": false, + "datamodel": [ + "src\/Service\/FilesInformation.php", + "src\/Service\/FilesInformationException.php", + "src\/Service\/FilesInformationUtils.php", + "src\/Service\/FilesIntegrity.php" + ], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-files-information\/module.itop-files-information.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-files-information", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-files-information\/module.itop-files-information.php", + "dictionary": [ + "2.x\/itop-files-information\/dictionaries\/sk.dict.itop-files-information.php", + "2.x\/itop-files-information\/dictionaries\/cs.dict.itop-files-information.php", + "2.x\/itop-files-information\/dictionaries\/ja.dict.itop-files-information.php", + "2.x\/itop-files-information\/dictionaries\/hu.dict.itop-files-information.php", + "2.x\/itop-files-information\/dictionaries\/en_gb.dict.itop-files-information.php", + "2.x\/itop-files-information\/dictionaries\/fr.dict.itop-files-information.php", + "2.x\/itop-files-information\/dictionaries\/pt_br.dict.itop-files-information.php", + "2.x\/itop-files-information\/dictionaries\/es_cr.dict.itop-files-information.php", + "2.x\/itop-files-information\/dictionaries\/tr.dict.itop-files-information.php", + "2.x\/itop-files-information\/dictionaries\/pl.dict.itop-files-information.php", + "2.x\/itop-files-information\/dictionaries\/zh_cn.dict.itop-files-information.php", + "2.x\/itop-files-information\/dictionaries\/en.dict.itop-files-information.php", + "2.x\/itop-files-information\/dictionaries\/da.dict.itop-files-information.php", + "2.x\/itop-files-information\/dictionaries\/de.dict.itop-files-information.php", + "2.x\/itop-files-information\/dictionaries\/nl.dict.itop-files-information.php", + "2.x\/itop-files-information\/dictionaries\/it.dict.itop-files-information.php", + "2.x\/itop-files-information\/dictionaries\/ru.dict.itop-files-information.php" + ] + }, + "itop-portal-base\/3.3.0": { + "label": "Portal Development Library", + "category": "Portal", + "dependencies": [], + "mandatory": true, + "visible": false, + "datamodel": [ + "portal\/vendor\/autoload.php" + ], + "webservice": [], + "dictionary": [ + "2.x\/itop-portal-base\/dictionaries\/en_gb.dict.itop-portal-base.php", + "2.x\/itop-portal-base\/dictionaries\/hu.dict.itop-portal-base.php", + "2.x\/itop-portal-base\/dictionaries\/ja.dict.itop-portal-base.php", + "2.x\/itop-portal-base\/dictionaries\/cs.dict.itop-portal-base.php", + "2.x\/itop-portal-base\/dictionaries\/zh_cn.dict.itop-portal-base.php", + "2.x\/itop-portal-base\/dictionaries\/tr.dict.itop-portal-base.php", + "2.x\/itop-portal-base\/dictionaries\/pt_br.dict.itop-portal-base.php", + "2.x\/itop-portal-base\/dictionaries\/nl.dict.itop-portal-base.php", + "2.x\/itop-portal-base\/dictionaries\/it.dict.itop-portal-base.php", + "2.x\/itop-portal-base\/dictionaries\/es_cr.dict.itop-portal-base.php", + "2.x\/itop-portal-base\/dictionaries\/fr.dict.itop-portal-base.php", + "2.x\/itop-portal-base\/dictionaries\/pl.dict.itop-portal-base.php", + "2.x\/itop-portal-base\/dictionaries\/ru.dict.itop-portal-base.php", + "2.x\/itop-portal-base\/dictionaries\/de.dict.itop-portal-base.php", + "2.x\/itop-portal-base\/dictionaries\/da.dict.itop-portal-base.php", + "2.x\/itop-portal-base\/dictionaries\/en.dict.itop-portal-base.php", + "2.x\/itop-portal-base\/dictionaries\/sk.dict.itop-portal-base.php" + ], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-portal-base\/module.itop-portal-base.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-portal-base", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-portal-base\/module.itop-portal-base.php" + }, + "itop-portal\/3.3.0": { + "label": "Enhanced Customer Portal", + "category": "Portal", + "dependencies": [ + "itop-portal-base\/2.7.0" + ], + "mandatory": false, + "visible": true, + "datamodel": [ + "main.itop-portal.php" + ], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-portal\/module.itop-portal.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-portal", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-portal\/module.itop-portal.php", + "dictionary": [ + "2.x\/itop-portal\/dictionaries\/de.dict.itop-portal.php", + "2.x\/itop-portal\/dictionaries\/ru.dict.itop-portal.php", + "2.x\/itop-portal\/dictionaries\/pl.dict.itop-portal.php", + "2.x\/itop-portal\/dictionaries\/ja.dict.itop-portal.php", + "2.x\/itop-portal\/dictionaries\/cs.dict.itop-portal.php", + "2.x\/itop-portal\/dictionaries\/zh_cn.dict.itop-portal.php", + "2.x\/itop-portal\/dictionaries\/en_gb.dict.itop-portal.php", + "2.x\/itop-portal\/dictionaries\/da.dict.itop-portal.php", + "2.x\/itop-portal\/dictionaries\/hu.dict.itop-portal.php", + "2.x\/itop-portal\/dictionaries\/it.dict.itop-portal.php", + "2.x\/itop-portal\/dictionaries\/tr.dict.itop-portal.php", + "2.x\/itop-portal\/dictionaries\/es_cr.dict.itop-portal.php", + "2.x\/itop-portal\/dictionaries\/sk.dict.itop-portal.php", + "2.x\/itop-portal\/dictionaries\/fr.dict.itop-portal.php", + "2.x\/itop-portal\/dictionaries\/nl.dict.itop-portal.php", + "2.x\/itop-portal\/dictionaries\/pt_br.dict.itop-portal.php", + "2.x\/itop-portal\/dictionaries\/en.dict.itop-portal.php" + ] + }, + "itop-profiles-itil\/3.3.0": { + "label": "Create standard ITIL profiles", + "category": "create_profiles", + "dependencies": [], + "mandatory": true, + "visible": false, + "datamodel": [], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-profiles-itil\/module.itop-profiles-itil.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-profiles-itil", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-profiles-itil\/module.itop-profiles-itil.php" + }, + "itop-sla-computation\/3.3.0": { + "label": "SLA Computation", + "category": "sla", + "dependencies": [], + "mandatory": true, + "visible": false, + "datamodel": [ + "main.itop-sla-computation.php" + ], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-sla-computation\/module.itop-sla-computation.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-sla-computation", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-sla-computation\/module.itop-sla-computation.php" + }, + "itop-structure\/3.3.0": { + "label": "Core iTop Structure", + "category": "business", + "dependencies": [], + "mandatory": true, + "visible": false, + "installer": "StructureInstaller", + "datamodel": [ + "main.itop-structure.php" + ], + "data.struct": [], + "data.sample": [ + "data.sample.organizations.xml", + "data.sample.locations.xml", + "data.sample.persons.xml", + "data.sample.teams.xml", + "data.sample.contactteam.xml", + "data.sample.contacttype.xml" + ], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-structure\/module.itop-structure.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-structure", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-structure\/module.itop-structure.php", + "dictionary": [ + "2.x\/itop-structure\/dictionaries\/sk.dict.itop-structure.php", + "2.x\/itop-structure\/dictionaries\/pl.dict.itop-structure.php", + "2.x\/itop-structure\/dictionaries\/fr.dict.itop-structure.php", + "2.x\/itop-structure\/dictionaries\/pt_br.dict.itop-structure.php", + "2.x\/itop-structure\/dictionaries\/da.dict.itop-structure.php", + "2.x\/itop-structure\/dictionaries\/ja.dict.itop-structure.php", + "2.x\/itop-structure\/dictionaries\/ru.dict.itop-structure.php", + "2.x\/itop-structure\/dictionaries\/tr.dict.itop-structure.php", + "2.x\/itop-structure\/dictionaries\/hu.dict.itop-structure.php", + "2.x\/itop-structure\/dictionaries\/nl.dict.itop-structure.php", + "2.x\/itop-structure\/dictionaries\/en_gb.dict.itop-structure.php", + "2.x\/itop-structure\/dictionaries\/en.dict.itop-structure.php", + "2.x\/itop-structure\/dictionaries\/it.dict.itop-structure.php", + "2.x\/itop-structure\/dictionaries\/de.dict.itop-structure.php", + "2.x\/itop-structure\/dictionaries\/cs.dict.itop-structure.php", + "2.x\/itop-structure\/dictionaries\/es_cr.dict.itop-structure.php", + "2.x\/itop-structure\/dictionaries\/zh_cn.dict.itop-structure.php" + ] + }, + "itop-themes-compat\/3.3.0": { + "label": "Light grey and Test red themes compatibility", + "category": "business", + "dependencies": [ + "itop-structure\/3.1.0" + ], + "mandatory": false, + "visible": true, + "datamodel": [], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-themes-compat\/module.itop-themes-compat.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-themes-compat", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-themes-compat\/module.itop-themes-compat.php", + "dictionary": [ + "2.x\/itop-themes-compat\/dictionaries\/it.dict.itop-themes-compat.php", + "2.x\/itop-themes-compat\/dictionaries\/tr.dict.itop-themes-compat.php", + "2.x\/itop-themes-compat\/dictionaries\/ru.dict.itop-themes-compat.php", + "2.x\/itop-themes-compat\/dictionaries\/pt_br.dict.itop-themes-compat.php", + "2.x\/itop-themes-compat\/dictionaries\/da.dict.itop-themes-compat.php", + "2.x\/itop-themes-compat\/dictionaries\/fr.dict.itop-themes-compat.php", + "2.x\/itop-themes-compat\/dictionaries\/ja.dict.itop-themes-compat.php", + "2.x\/itop-themes-compat\/dictionaries\/hu.dict.itop-themes-compat.php", + "2.x\/itop-themes-compat\/dictionaries\/en_gb.dict.itop-themes-compat.php", + "2.x\/itop-themes-compat\/dictionaries\/cs.dict.itop-themes-compat.php", + "2.x\/itop-themes-compat\/dictionaries\/nl.dict.itop-themes-compat.php", + "2.x\/itop-themes-compat\/dictionaries\/sk.dict.itop-themes-compat.php", + "2.x\/itop-themes-compat\/dictionaries\/de.dict.itop-themes-compat.php", + "2.x\/itop-themes-compat\/dictionaries\/es_cr.dict.itop-themes-compat.php", + "2.x\/itop-themes-compat\/dictionaries\/zh_cn.dict.itop-themes-compat.php", + "2.x\/itop-themes-compat\/dictionaries\/pl.dict.itop-themes-compat.php", + "2.x\/itop-themes-compat\/dictionaries\/en.dict.itop-themes-compat.php" + ] + }, + "itop-tickets\/3.3.0": { + "label": "Tickets Management", + "category": "business", + "dependencies": [ + "itop-structure\/2.7.1" + ], + "mandatory": false, + "visible": true, + "installer": "TicketsInstaller", + "datamodel": [ + "main.itop-tickets.php" + ], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-tickets\/module.itop-tickets.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-tickets", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-tickets\/module.itop-tickets.php", + "dictionary": [ + "2.x\/itop-tickets\/dictionaries\/cs.dict.itop-tickets.php", + "2.x\/itop-tickets\/dictionaries\/da.dict.itop-tickets.php", + "2.x\/itop-tickets\/dictionaries\/es_cr.dict.itop-tickets.php", + "2.x\/itop-tickets\/dictionaries\/tr.dict.itop-tickets.php", + "2.x\/itop-tickets\/dictionaries\/nl.dict.itop-tickets.php", + "2.x\/itop-tickets\/dictionaries\/pl.dict.itop-tickets.php", + "2.x\/itop-tickets\/dictionaries\/it.dict.itop-tickets.php", + "2.x\/itop-tickets\/dictionaries\/en.dict.itop-tickets.php", + "2.x\/itop-tickets\/dictionaries\/pt_br.dict.itop-tickets.php", + "2.x\/itop-tickets\/dictionaries\/fr.dict.itop-tickets.php", + "2.x\/itop-tickets\/dictionaries\/sk.dict.itop-tickets.php", + "2.x\/itop-tickets\/dictionaries\/ja.dict.itop-tickets.php", + "2.x\/itop-tickets\/dictionaries\/ru.dict.itop-tickets.php", + "2.x\/itop-tickets\/dictionaries\/hu.dict.itop-tickets.php", + "2.x\/itop-tickets\/dictionaries\/de.dict.itop-tickets.php", + "2.x\/itop-tickets\/dictionaries\/en_gb.dict.itop-tickets.php", + "2.x\/itop-tickets\/dictionaries\/zh_cn.dict.itop-tickets.php" + ] + }, + "itop-welcome-itil\/3.3.0": { + "label": "ITIL skin", + "category": "skin", + "dependencies": [], + "mandatory": true, + "visible": false, + "datamodel": [], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-welcome-itil\/module.itop-welcome-itil.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-welcome-itil", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-welcome-itil\/module.itop-welcome-itil.php", + "dictionary": [ + "2.x\/itop-welcome-itil\/dictionaries\/da.dict.itop-welcome-itil.php", + "2.x\/itop-welcome-itil\/dictionaries\/es_cr.dict.itop-welcome-itil.php", + "2.x\/itop-welcome-itil\/dictionaries\/sk.dict.itop-welcome-itil.php", + "2.x\/itop-welcome-itil\/dictionaries\/nl.dict.itop-welcome-itil.php", + "2.x\/itop-welcome-itil\/dictionaries\/en.dict.itop-welcome-itil.php", + "2.x\/itop-welcome-itil\/dictionaries\/fr.dict.itop-welcome-itil.php", + "2.x\/itop-welcome-itil\/dictionaries\/ru.dict.itop-welcome-itil.php", + "2.x\/itop-welcome-itil\/dictionaries\/ja.dict.itop-welcome-itil.php", + "2.x\/itop-welcome-itil\/dictionaries\/de.dict.itop-welcome-itil.php", + "2.x\/itop-welcome-itil\/dictionaries\/it.dict.itop-welcome-itil.php", + "2.x\/itop-welcome-itil\/dictionaries\/pl.dict.itop-welcome-itil.php", + "2.x\/itop-welcome-itil\/dictionaries\/tr.dict.itop-welcome-itil.php", + "2.x\/itop-welcome-itil\/dictionaries\/en_gb.dict.itop-welcome-itil.php", + "2.x\/itop-welcome-itil\/dictionaries\/hu.dict.itop-welcome-itil.php", + "2.x\/itop-welcome-itil\/dictionaries\/zh_cn.dict.itop-welcome-itil.php", + "2.x\/itop-welcome-itil\/dictionaries\/cs.dict.itop-welcome-itil.php", + "2.x\/itop-welcome-itil\/dictionaries\/pt_br.dict.itop-welcome-itil.php" + ] + }, + "combodo-db-tools\/3.3.0": { + "label": "Database maintenance tools", + "category": "business", + "dependencies": [ + "itop-structure\/3.0.0" + ], + "mandatory": false, + "visible": true, + "datamodel": [ + "src\/Service\/DBToolsUtils.php", + "src\/Service\/DBAnalyzerUtils.php" + ], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/combodo-db-tools\/module.combodo-db-tools.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/combodo-db-tools", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/combodo-db-tools\/module.combodo-db-tools.php", + "dictionary": [ + "2.x\/combodo-db-tools\/dictionaries\/en.dict.combodo-db-tools.php", + "2.x\/combodo-db-tools\/dictionaries\/pl.dict.combodo-db-tools.php", + "2.x\/combodo-db-tools\/dictionaries\/pt_br.dict.combodo-db-tools.php", + "2.x\/combodo-db-tools\/dictionaries\/zh_cn.dict.combodo-db-tools.php", + "2.x\/combodo-db-tools\/dictionaries\/en_gb.dict.combodo-db-tools.php", + "2.x\/combodo-db-tools\/dictionaries\/nl.dict.combodo-db-tools.php", + "2.x\/combodo-db-tools\/dictionaries\/ru.dict.combodo-db-tools.php", + "2.x\/combodo-db-tools\/dictionaries\/es_cr.dict.combodo-db-tools.php", + "2.x\/combodo-db-tools\/dictionaries\/tr.dict.combodo-db-tools.php", + "2.x\/combodo-db-tools\/dictionaries\/da.dict.combodo-db-tools.php", + "2.x\/combodo-db-tools\/dictionaries\/ja.dict.combodo-db-tools.php", + "2.x\/combodo-db-tools\/dictionaries\/de.dict.combodo-db-tools.php", + "2.x\/combodo-db-tools\/dictionaries\/hu.dict.combodo-db-tools.php", + "2.x\/combodo-db-tools\/dictionaries\/fr.dict.combodo-db-tools.php", + "2.x\/combodo-db-tools\/dictionaries\/it.dict.combodo-db-tools.php", + "2.x\/combodo-db-tools\/dictionaries\/sk.dict.combodo-db-tools.php", + "2.x\/combodo-db-tools\/dictionaries\/cs.dict.combodo-db-tools.php" + ] + }, + "itop-config-mgmt\/3.3.0": { + "label": "Configuration Management (CMDB)", + "category": "business", + "dependencies": [ + "itop-structure\/2.7.1" + ], + "mandatory": false, + "visible": true, + "installer": "ConfigMgmtInstaller", + "datamodel": [ + "model.itop-config-mgmt.php", + "main.itop-config-mgmt.php" + ], + "data.struct": [ + "data\/en_us.data.itop-brand.xml", + "data\/en_us.data.itop-osfamily.xml", + "data\/en_us.data.itop-osversion.xml" + ], + "data.sample": [ + "data.sample.model.xml", + "data.sample.networkdevicetype.xml", + "data.sample.servers.xml", + "data.sample.nw-devices.xml", + "data.sample.software.xml", + "data.sample.dbserver.xml", + "data.sample.dbschema.xml", + "data.sample.webserver.xml", + "data.sample.webapp.xml", + "data.sample.applications.xml", + "data.sample.applicationsolutionci.xml" + ], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-config-mgmt\/module.itop-config-mgmt.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-config-mgmt", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-config-mgmt\/module.itop-config-mgmt.php", + "dictionary": [ + "2.x\/itop-config-mgmt\/dictionaries\/ru.dict.itop-config-mgmt.php", + "2.x\/itop-config-mgmt\/dictionaries\/tr.dict.itop-config-mgmt.php", + "2.x\/itop-config-mgmt\/dictionaries\/it.dict.itop-config-mgmt.php", + "2.x\/itop-config-mgmt\/dictionaries\/pl.dict.itop-config-mgmt.php", + "2.x\/itop-config-mgmt\/dictionaries\/de.dict.itop-config-mgmt.php", + "2.x\/itop-config-mgmt\/dictionaries\/en_gb.dict.itop-config-mgmt.php", + "2.x\/itop-config-mgmt\/dictionaries\/fr.dict.itop-config-mgmt.php", + "2.x\/itop-config-mgmt\/dictionaries\/hu.dict.itop-config-mgmt.php", + "2.x\/itop-config-mgmt\/dictionaries\/nl.dict.itop-config-mgmt.php", + "2.x\/itop-config-mgmt\/dictionaries\/en.dict.itop-config-mgmt.php", + "2.x\/itop-config-mgmt\/dictionaries\/cs.dict.itop-config-mgmt.php", + "2.x\/itop-config-mgmt\/dictionaries\/ja.dict.itop-config-mgmt.php", + "2.x\/itop-config-mgmt\/dictionaries\/sk.dict.itop-config-mgmt.php", + "2.x\/itop-config-mgmt\/dictionaries\/zh_cn.dict.itop-config-mgmt.php", + "2.x\/itop-config-mgmt\/dictionaries\/da.dict.itop-config-mgmt.php", + "2.x\/itop-config-mgmt\/dictionaries\/pt_br.dict.itop-config-mgmt.php", + "2.x\/itop-config-mgmt\/dictionaries\/es_cr.dict.itop-config-mgmt.php" + ] + }, + "itop-core-update\/3.3.0": { + "label": "iTop Core Update", + "category": "business", + "dependencies": [ + "itop-files-information\/2.7.0", + "combodo-db-tools\/2.7.0" + ], + "mandatory": false, + "visible": true, + "datamodel": [ + "src\/Service\/RunTimeEnvironmentCoreUpdater.php", + "src\/Service\/CoreUpdater.php", + "src\/Controller\/UpdateController.php", + "src\/Controller\/AjaxController.php" + ], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-core-update\/module.itop-core-update.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-core-update", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-core-update\/module.itop-core-update.php", + "dictionary": [ + "2.x\/itop-core-update\/dictionaries\/ru.dict.itop-core-update.php", + "2.x\/itop-core-update\/dictionaries\/de.dict.itop-core-update.php", + "2.x\/itop-core-update\/dictionaries\/hu.dict.itop-core-update.php", + "2.x\/itop-core-update\/dictionaries\/es_cr.dict.itop-core-update.php", + "2.x\/itop-core-update\/dictionaries\/cs.dict.itop-core-update.php", + "2.x\/itop-core-update\/dictionaries\/sk.dict.itop-core-update.php", + "2.x\/itop-core-update\/dictionaries\/pl.dict.itop-core-update.php", + "2.x\/itop-core-update\/dictionaries\/zh_cn.dict.itop-core-update.php", + "2.x\/itop-core-update\/dictionaries\/fr.dict.itop-core-update.php", + "2.x\/itop-core-update\/dictionaries\/da.dict.itop-core-update.php", + "2.x\/itop-core-update\/dictionaries\/en_gb.dict.itop-core-update.php", + "2.x\/itop-core-update\/dictionaries\/it.dict.itop-core-update.php", + "2.x\/itop-core-update\/dictionaries\/pt_br.dict.itop-core-update.php", + "2.x\/itop-core-update\/dictionaries\/en.dict.itop-core-update.php", + "2.x\/itop-core-update\/dictionaries\/nl.dict.itop-core-update.php", + "2.x\/itop-core-update\/dictionaries\/tr.dict.itop-core-update.php", + "2.x\/itop-core-update\/dictionaries\/ja.dict.itop-core-update.php" + ] + }, + "itop-datacenter-mgmt\/3.3.0": { + "label": "Datacenter Management", + "category": "business", + "dependencies": [ + "itop-config-mgmt\/2.2.0" + ], + "mandatory": false, + "visible": true, + "datamodel": [], + "webservice": [], + "data.struct": [], + "data.sample": [ + "data.sample.racks.xml" + ], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-datacenter-mgmt\/module.itop-datacenter-mgmt.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-datacenter-mgmt", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-datacenter-mgmt\/module.itop-datacenter-mgmt.php", + "dictionary": [ + "2.x\/itop-datacenter-mgmt\/dictionaries\/tr.dict.itop-datacenter-mgmt.php", + "2.x\/itop-datacenter-mgmt\/dictionaries\/ja.dict.itop-datacenter-mgmt.php", + "2.x\/itop-datacenter-mgmt\/dictionaries\/sk.dict.itop-datacenter-mgmt.php", + "2.x\/itop-datacenter-mgmt\/dictionaries\/da.dict.itop-datacenter-mgmt.php", + "2.x\/itop-datacenter-mgmt\/dictionaries\/es_cr.dict.itop-datacenter-mgmt.php", + "2.x\/itop-datacenter-mgmt\/dictionaries\/pl.dict.itop-datacenter-mgmt.php", + "2.x\/itop-datacenter-mgmt\/dictionaries\/ru.dict.itop-datacenter-mgmt.php", + "2.x\/itop-datacenter-mgmt\/dictionaries\/en.dict.itop-datacenter-mgmt.php", + "2.x\/itop-datacenter-mgmt\/dictionaries\/it.dict.itop-datacenter-mgmt.php", + "2.x\/itop-datacenter-mgmt\/dictionaries\/zh_cn.dict.itop-datacenter-mgmt.php", + "2.x\/itop-datacenter-mgmt\/dictionaries\/de.dict.itop-datacenter-mgmt.php", + "2.x\/itop-datacenter-mgmt\/dictionaries\/hu.dict.itop-datacenter-mgmt.php", + "2.x\/itop-datacenter-mgmt\/dictionaries\/cs.dict.itop-datacenter-mgmt.php", + "2.x\/itop-datacenter-mgmt\/dictionaries\/en_gb.dict.itop-datacenter-mgmt.php", + "2.x\/itop-datacenter-mgmt\/dictionaries\/fr.dict.itop-datacenter-mgmt.php", + "2.x\/itop-datacenter-mgmt\/dictionaries\/pt_br.dict.itop-datacenter-mgmt.php", + "2.x\/itop-datacenter-mgmt\/dictionaries\/nl.dict.itop-datacenter-mgmt.php" + ] + }, + "itop-endusers-devices\/3.3.0": { + "label": "End-user Devices Management", + "category": "business", + "dependencies": [ + "itop-config-mgmt\/2.2.0" + ], + "mandatory": false, + "visible": true, + "installer": "EndUserMgmtInstaller", + "datamodel": [], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-endusers-devices\/module.itop-endusers-devices.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-endusers-devices", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-endusers-devices\/module.itop-endusers-devices.php", + "dictionary": [ + "2.x\/itop-endusers-devices\/dictionaries\/pl.dict.itop-endusers-devices.php", + "2.x\/itop-endusers-devices\/dictionaries\/cs.dict.itop-endusers-devices.php", + "2.x\/itop-endusers-devices\/dictionaries\/en.dict.itop-endusers-devices.php", + "2.x\/itop-endusers-devices\/dictionaries\/ru.dict.itop-endusers-devices.php", + "2.x\/itop-endusers-devices\/dictionaries\/it.dict.itop-endusers-devices.php", + "2.x\/itop-endusers-devices\/dictionaries\/en_gb.dict.itop-endusers-devices.php", + "2.x\/itop-endusers-devices\/dictionaries\/sk.dict.itop-endusers-devices.php", + "2.x\/itop-endusers-devices\/dictionaries\/es_cr.dict.itop-endusers-devices.php", + "2.x\/itop-endusers-devices\/dictionaries\/de.dict.itop-endusers-devices.php", + "2.x\/itop-endusers-devices\/dictionaries\/fr.dict.itop-endusers-devices.php", + "2.x\/itop-endusers-devices\/dictionaries\/tr.dict.itop-endusers-devices.php", + "2.x\/itop-endusers-devices\/dictionaries\/hu.dict.itop-endusers-devices.php", + "2.x\/itop-endusers-devices\/dictionaries\/da.dict.itop-endusers-devices.php", + "2.x\/itop-endusers-devices\/dictionaries\/zh_cn.dict.itop-endusers-devices.php", + "2.x\/itop-endusers-devices\/dictionaries\/nl.dict.itop-endusers-devices.php", + "2.x\/itop-endusers-devices\/dictionaries\/ja.dict.itop-endusers-devices.php", + "2.x\/itop-endusers-devices\/dictionaries\/pt_br.dict.itop-endusers-devices.php" + ] + }, + "itop-faq-light\/3.3.0": { + "label": "Frequently Asked Questions Database", + "category": "business", + "dependencies": [ + "itop-structure\/3.0.0 || itop-portal\/3.0.0" + ], + "mandatory": false, + "visible": true, + "installer": "FAQLightInstaller", + "datamodel": [], + "data.struct": [], + "data.sample": [ + "data.sample.faq-domains.xml" + ], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-faq-light\/module.itop-faq-light.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-faq-light", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-faq-light\/module.itop-faq-light.php", + "dictionary": [ + "2.x\/itop-faq-light\/dictionaries\/pl.dict.itop-faq-light.php", + "2.x\/itop-faq-light\/dictionaries\/da.dict.itop-faq-light.php", + "2.x\/itop-faq-light\/dictionaries\/en.dict.itop-faq-light.php", + "2.x\/itop-faq-light\/dictionaries\/zh_cn.dict.itop-faq-light.php", + "2.x\/itop-faq-light\/dictionaries\/es_cr.dict.itop-faq-light.php", + "2.x\/itop-faq-light\/dictionaries\/nl.dict.itop-faq-light.php", + "2.x\/itop-faq-light\/dictionaries\/pt_br.dict.itop-faq-light.php", + "2.x\/itop-faq-light\/dictionaries\/cs.dict.itop-faq-light.php", + "2.x\/itop-faq-light\/dictionaries\/ru.dict.itop-faq-light.php", + "2.x\/itop-faq-light\/dictionaries\/en_gb.dict.itop-faq-light.php", + "2.x\/itop-faq-light\/dictionaries\/tr.dict.itop-faq-light.php", + "2.x\/itop-faq-light\/dictionaries\/it.dict.itop-faq-light.php", + "2.x\/itop-faq-light\/dictionaries\/fr.dict.itop-faq-light.php", + "2.x\/itop-faq-light\/dictionaries\/hu.dict.itop-faq-light.php", + "2.x\/itop-faq-light\/dictionaries\/sk.dict.itop-faq-light.php", + "2.x\/itop-faq-light\/dictionaries\/de.dict.itop-faq-light.php", + "2.x\/itop-faq-light\/dictionaries\/ja.dict.itop-faq-light.php" + ] + }, + "itop-hub-connector\/3.3.0": { + "label": "iTop Hub Connector", + "category": "business", + "dependencies": [ + "itop-config-mgmt\/2.4.0" + ], + "mandatory": false, + "visible": true, + "datamodel": [ + "menus.php", + "hubnewsroomprovider.class.inc.php" + ], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-hub-connector\/module.itop-hub-connector.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-hub-connector", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-hub-connector\/module.itop-hub-connector.php", + "dictionary": [ + "2.x\/itop-hub-connector\/dictionaries\/en_gb.dict.itop-hub-connector.php", + "2.x\/itop-hub-connector\/dictionaries\/it.dict.itop-hub-connector.php", + "2.x\/itop-hub-connector\/dictionaries\/zh_cn.dict.itop-hub-connector.php", + "2.x\/itop-hub-connector\/dictionaries\/sk.dict.itop-hub-connector.php", + "2.x\/itop-hub-connector\/dictionaries\/cs.dict.itop-hub-connector.php", + "2.x\/itop-hub-connector\/dictionaries\/fr.dict.itop-hub-connector.php", + "2.x\/itop-hub-connector\/dictionaries\/hu.dict.itop-hub-connector.php", + "2.x\/itop-hub-connector\/dictionaries\/ru.dict.itop-hub-connector.php", + "2.x\/itop-hub-connector\/dictionaries\/ja.dict.itop-hub-connector.php", + "2.x\/itop-hub-connector\/dictionaries\/en.dict.itop-hub-connector.php", + "2.x\/itop-hub-connector\/dictionaries\/es_cr.dict.itop-hub-connector.php", + "2.x\/itop-hub-connector\/dictionaries\/tr.dict.itop-hub-connector.php", + "2.x\/itop-hub-connector\/dictionaries\/nl.dict.itop-hub-connector.php", + "2.x\/itop-hub-connector\/dictionaries\/pl.dict.itop-hub-connector.php", + "2.x\/itop-hub-connector\/dictionaries\/de.dict.itop-hub-connector.php", + "2.x\/itop-hub-connector\/dictionaries\/pt_br.dict.itop-hub-connector.php", + "2.x\/itop-hub-connector\/dictionaries\/da.dict.itop-hub-connector.php" + ] + }, + "itop-incident-mgmt-itil\/3.3.0": { + "label": "Incident Management ITIL", + "category": "business", + "dependencies": [ + "itop-config-mgmt\/2.4.0", + "itop-tickets\/2.4.0", + "itop-profiles-itil\/2.3.0" + ], + "mandatory": false, + "visible": true, + "datamodel": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-incident-mgmt-itil\/module.itop-incident-mgmt-itil.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-incident-mgmt-itil", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-incident-mgmt-itil\/module.itop-incident-mgmt-itil.php", + "dictionary": [ + "2.x\/itop-incident-mgmt-itil\/dictionaries\/en_gb.dict.itop-incident-mgmt-itil.php", + "2.x\/itop-incident-mgmt-itil\/dictionaries\/da.dict.itop-incident-mgmt-itil.php", + "2.x\/itop-incident-mgmt-itil\/dictionaries\/en.dict.itop-incident-mgmt-itil.php", + "2.x\/itop-incident-mgmt-itil\/dictionaries\/de.dict.itop-incident-mgmt-itil.php", + "2.x\/itop-incident-mgmt-itil\/dictionaries\/zh_cn.dict.itop-incident-mgmt-itil.php", + "2.x\/itop-incident-mgmt-itil\/dictionaries\/sk.dict.itop-incident-mgmt-itil.php", + "2.x\/itop-incident-mgmt-itil\/dictionaries\/fr.dict.itop-incident-mgmt-itil.php", + "2.x\/itop-incident-mgmt-itil\/dictionaries\/hu.dict.itop-incident-mgmt-itil.php", + "2.x\/itop-incident-mgmt-itil\/dictionaries\/ja.dict.itop-incident-mgmt-itil.php", + "2.x\/itop-incident-mgmt-itil\/dictionaries\/pl.dict.itop-incident-mgmt-itil.php", + "2.x\/itop-incident-mgmt-itil\/dictionaries\/cs.dict.itop-incident-mgmt-itil.php", + "2.x\/itop-incident-mgmt-itil\/dictionaries\/nl.dict.itop-incident-mgmt-itil.php", + "2.x\/itop-incident-mgmt-itil\/dictionaries\/ru.dict.itop-incident-mgmt-itil.php", + "2.x\/itop-incident-mgmt-itil\/dictionaries\/tr.dict.itop-incident-mgmt-itil.php", + "2.x\/itop-incident-mgmt-itil\/dictionaries\/it.dict.itop-incident-mgmt-itil.php", + "2.x\/itop-incident-mgmt-itil\/dictionaries\/pt_br.dict.itop-incident-mgmt-itil.php", + "2.x\/itop-incident-mgmt-itil\/dictionaries\/es_cr.dict.itop-incident-mgmt-itil.php" + ] + }, + "itop-knownerror-mgmt\/3.3.0": { + "label": "Known Errors Database", + "category": "business", + "dependencies": [ + "itop-config-mgmt\/2.2.0" + ], + "mandatory": false, + "visible": true, + "datamodel": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-knownerror-mgmt\/module.itop-knownerror-mgmt.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-knownerror-mgmt", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-knownerror-mgmt\/module.itop-knownerror-mgmt.php", + "dictionary": [ + "2.x\/itop-knownerror-mgmt\/dictionaries\/hu.dict.itop-knownerror-mgmt.php", + "2.x\/itop-knownerror-mgmt\/dictionaries\/nl.dict.itop-knownerror-mgmt.php", + "2.x\/itop-knownerror-mgmt\/dictionaries\/cs.dict.itop-knownerror-mgmt.php", + "2.x\/itop-knownerror-mgmt\/dictionaries\/es_cr.dict.itop-knownerror-mgmt.php", + "2.x\/itop-knownerror-mgmt\/dictionaries\/fr.dict.itop-knownerror-mgmt.php", + "2.x\/itop-knownerror-mgmt\/dictionaries\/ru.dict.itop-knownerror-mgmt.php", + "2.x\/itop-knownerror-mgmt\/dictionaries\/en.dict.itop-knownerror-mgmt.php", + "2.x\/itop-knownerror-mgmt\/dictionaries\/da.dict.itop-knownerror-mgmt.php", + "2.x\/itop-knownerror-mgmt\/dictionaries\/it.dict.itop-knownerror-mgmt.php", + "2.x\/itop-knownerror-mgmt\/dictionaries\/sk.dict.itop-knownerror-mgmt.php", + "2.x\/itop-knownerror-mgmt\/dictionaries\/pt_br.dict.itop-knownerror-mgmt.php", + "2.x\/itop-knownerror-mgmt\/dictionaries\/tr.dict.itop-knownerror-mgmt.php", + "2.x\/itop-knownerror-mgmt\/dictionaries\/zh_cn.dict.itop-knownerror-mgmt.php", + "2.x\/itop-knownerror-mgmt\/dictionaries\/de.dict.itop-knownerror-mgmt.php", + "2.x\/itop-knownerror-mgmt\/dictionaries\/en_gb.dict.itop-knownerror-mgmt.php", + "2.x\/itop-knownerror-mgmt\/dictionaries\/pl.dict.itop-knownerror-mgmt.php", + "2.x\/itop-knownerror-mgmt\/dictionaries\/ja.dict.itop-knownerror-mgmt.php" + ] + }, + "itop-oauth-client\/3.3.0": { + "label": "OAuth 2.0 client", + "category": "business", + "dependencies": [ + "itop-welcome-itil\/3.1.0," + ], + "mandatory": false, + "visible": true, + "datamodel": [ + "vendor\/autoload.php", + "src\/Service\/PopupMenuExtension.php", + "src\/Service\/ApplicationUIExtension.php" + ], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-oauth-client\/module.itop-oauth-client.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-oauth-client", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-oauth-client\/module.itop-oauth-client.php", + "dictionary": [ + "2.x\/itop-oauth-client\/dictionaries\/tr.dict.itop-oauth-client.php", + "2.x\/itop-oauth-client\/dictionaries\/fr.dict.itop-oauth-client.php", + "2.x\/itop-oauth-client\/dictionaries\/it.dict.itop-oauth-client.php", + "2.x\/itop-oauth-client\/dictionaries\/en.dict.itop-oauth-client.php", + "2.x\/itop-oauth-client\/dictionaries\/cs.dict.itop-oauth-client.php", + "2.x\/itop-oauth-client\/dictionaries\/sk.dict.itop-oauth-client.php", + "2.x\/itop-oauth-client\/dictionaries\/pl.dict.itop-oauth-client.php", + "2.x\/itop-oauth-client\/dictionaries\/ru.dict.itop-oauth-client.php", + "2.x\/itop-oauth-client\/dictionaries\/zh_cn.dict.itop-oauth-client.php", + "2.x\/itop-oauth-client\/dictionaries\/pt_br.dict.itop-oauth-client.php", + "2.x\/itop-oauth-client\/dictionaries\/es_cr.dict.itop-oauth-client.php", + "2.x\/itop-oauth-client\/dictionaries\/nl.dict.itop-oauth-client.php", + "2.x\/itop-oauth-client\/dictionaries\/ja.dict.itop-oauth-client.php", + "2.x\/itop-oauth-client\/dictionaries\/de.dict.itop-oauth-client.php", + "2.x\/itop-oauth-client\/dictionaries\/hu.dict.itop-oauth-client.php", + "2.x\/itop-oauth-client\/dictionaries\/en_gb.dict.itop-oauth-client.php", + "2.x\/itop-oauth-client\/dictionaries\/da.dict.itop-oauth-client.php" + ] + }, + "itop-problem-mgmt\/3.3.0": { + "label": "Problem Management", + "category": "business", + "dependencies": [ + "itop-tickets\/2.0.0" + ], + "mandatory": false, + "visible": true, + "datamodel": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-problem-mgmt\/module.itop-problem-mgmt.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-problem-mgmt", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-problem-mgmt\/module.itop-problem-mgmt.php", + "dictionary": [ + "2.x\/itop-problem-mgmt\/dictionaries\/tr.dict.itop-problem-mgmt.php", + "2.x\/itop-problem-mgmt\/dictionaries\/cs.dict.itop-problem-mgmt.php", + "2.x\/itop-problem-mgmt\/dictionaries\/sk.dict.itop-problem-mgmt.php", + "2.x\/itop-problem-mgmt\/dictionaries\/pt_br.dict.itop-problem-mgmt.php", + "2.x\/itop-problem-mgmt\/dictionaries\/es_cr.dict.itop-problem-mgmt.php", + "2.x\/itop-problem-mgmt\/dictionaries\/en_gb.dict.itop-problem-mgmt.php", + "2.x\/itop-problem-mgmt\/dictionaries\/da.dict.itop-problem-mgmt.php", + "2.x\/itop-problem-mgmt\/dictionaries\/ru.dict.itop-problem-mgmt.php", + "2.x\/itop-problem-mgmt\/dictionaries\/pl.dict.itop-problem-mgmt.php", + "2.x\/itop-problem-mgmt\/dictionaries\/en.dict.itop-problem-mgmt.php", + "2.x\/itop-problem-mgmt\/dictionaries\/hu.dict.itop-problem-mgmt.php", + "2.x\/itop-problem-mgmt\/dictionaries\/fr.dict.itop-problem-mgmt.php", + "2.x\/itop-problem-mgmt\/dictionaries\/nl.dict.itop-problem-mgmt.php", + "2.x\/itop-problem-mgmt\/dictionaries\/ja.dict.itop-problem-mgmt.php", + "2.x\/itop-problem-mgmt\/dictionaries\/de.dict.itop-problem-mgmt.php", + "2.x\/itop-problem-mgmt\/dictionaries\/zh_cn.dict.itop-problem-mgmt.php", + "2.x\/itop-problem-mgmt\/dictionaries\/it.dict.itop-problem-mgmt.php" + ] + }, + "itop-request-mgmt-itil\/3.3.0": { + "label": "User request Management ITIL", + "category": "business", + "dependencies": [ + "itop-tickets\/2.4.0" + ], + "mandatory": false, + "visible": true, + "datamodel": [ + "main.itop-request-mgmt-itil.php" + ], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-request-mgmt-itil\/module.itop-request-mgmt-itil.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-request-mgmt-itil", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-request-mgmt-itil\/module.itop-request-mgmt-itil.php", + "dictionary": [ + "2.x\/itop-request-mgmt-itil\/dictionaries\/ja.dict.itop-request-mgmt-itil.php", + "2.x\/itop-request-mgmt-itil\/dictionaries\/hu.dict.itop-request-mgmt-itil.php", + "2.x\/itop-request-mgmt-itil\/dictionaries\/fr.dict.itop-request-mgmt-itil.php", + "2.x\/itop-request-mgmt-itil\/dictionaries\/nl.dict.itop-request-mgmt-itil.php", + "2.x\/itop-request-mgmt-itil\/dictionaries\/ru.dict.itop-request-mgmt-itil.php", + "2.x\/itop-request-mgmt-itil\/dictionaries\/zh_cn.dict.itop-request-mgmt-itil.php", + "2.x\/itop-request-mgmt-itil\/dictionaries\/it.dict.itop-request-mgmt-itil.php", + "2.x\/itop-request-mgmt-itil\/dictionaries\/pl.dict.itop-request-mgmt-itil.php", + "2.x\/itop-request-mgmt-itil\/dictionaries\/pt_br.dict.itop-request-mgmt-itil.php", + "2.x\/itop-request-mgmt-itil\/dictionaries\/sk.dict.itop-request-mgmt-itil.php", + "2.x\/itop-request-mgmt-itil\/dictionaries\/tr.dict.itop-request-mgmt-itil.php", + "2.x\/itop-request-mgmt-itil\/dictionaries\/es_cr.dict.itop-request-mgmt-itil.php", + "2.x\/itop-request-mgmt-itil\/dictionaries\/en_gb.dict.itop-request-mgmt-itil.php", + "2.x\/itop-request-mgmt-itil\/dictionaries\/de.dict.itop-request-mgmt-itil.php", + "2.x\/itop-request-mgmt-itil\/dictionaries\/en.dict.itop-request-mgmt-itil.php", + "2.x\/itop-request-mgmt-itil\/dictionaries\/cs.dict.itop-request-mgmt-itil.php", + "2.x\/itop-request-mgmt-itil\/dictionaries\/da.dict.itop-request-mgmt-itil.php" + ] + }, + "itop-request-mgmt\/3.3.0": { + "label": "Simple Ticket Management", + "category": "business", + "dependencies": [ + "itop-tickets\/2.4.0" + ], + "mandatory": false, + "visible": true, + "datamodel": [ + "main.itop-request-mgmt.php" + ], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-request-mgmt\/module.itop-request-mgmt.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-request-mgmt", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-request-mgmt\/module.itop-request-mgmt.php", + "dictionary": [ + "2.x\/itop-request-mgmt\/dictionaries\/tr.dict.itop-request-mgmt.php", + "2.x\/itop-request-mgmt\/dictionaries\/da.dict.itop-request-mgmt.php", + "2.x\/itop-request-mgmt\/dictionaries\/it.dict.itop-request-mgmt.php", + "2.x\/itop-request-mgmt\/dictionaries\/fr.dict.itop-request-mgmt.php", + "2.x\/itop-request-mgmt\/dictionaries\/ru.dict.itop-request-mgmt.php", + "2.x\/itop-request-mgmt\/dictionaries\/cs.dict.itop-request-mgmt.php", + "2.x\/itop-request-mgmt\/dictionaries\/hu.dict.itop-request-mgmt.php", + "2.x\/itop-request-mgmt\/dictionaries\/en.dict.itop-request-mgmt.php", + "2.x\/itop-request-mgmt\/dictionaries\/pl.dict.itop-request-mgmt.php", + "2.x\/itop-request-mgmt\/dictionaries\/sk.dict.itop-request-mgmt.php", + "2.x\/itop-request-mgmt\/dictionaries\/pt_br.dict.itop-request-mgmt.php", + "2.x\/itop-request-mgmt\/dictionaries\/zh_cn.dict.itop-request-mgmt.php", + "2.x\/itop-request-mgmt\/dictionaries\/de.dict.itop-request-mgmt.php", + "2.x\/itop-request-mgmt\/dictionaries\/es_cr.dict.itop-request-mgmt.php", + "2.x\/itop-request-mgmt\/dictionaries\/en_gb.dict.itop-request-mgmt.php", + "2.x\/itop-request-mgmt\/dictionaries\/nl.dict.itop-request-mgmt.php", + "2.x\/itop-request-mgmt\/dictionaries\/ja.dict.itop-request-mgmt.php" + ] + }, + "itop-service-mgmt-provider\/3.3.0": { + "label": "Service Management for Service Providers", + "category": "business", + "dependencies": [ + "itop-tickets\/2.0.0" + ], + "mandatory": false, + "visible": true, + "installer": "ServiceMgmtProviderInstaller", + "datamodel": [], + "data.struct": [], + "data.sample": [ + "data.sample.organizations.xml", + "data.sample.contracts.xml", + "data.sample.servicefamilies.xml", + "data.sample.services.xml", + "data.sample.serviceelements.xml", + "data.sample.sla.xml", + "data.sample.slt.xml", + "data.sample.sltsla.xml", + "data.sample.contractservice.xml", + "data.sample.deliverymodelcontact.xml" + ], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-service-mgmt-provider\/module.itop-service-mgmt-provider.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-service-mgmt-provider", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-service-mgmt-provider\/module.itop-service-mgmt-provider.php", + "dictionary": [ + "2.x\/itop-service-mgmt-provider\/dictionaries\/zh_cn.dict.itop-service-mgmt-provider.php", + "2.x\/itop-service-mgmt-provider\/dictionaries\/tr.dict.itop-service-mgmt-provider.php", + "2.x\/itop-service-mgmt-provider\/dictionaries\/sk.dict.itop-service-mgmt-provider.php", + "2.x\/itop-service-mgmt-provider\/dictionaries\/de.dict.itop-service-mgmt-provider.php", + "2.x\/itop-service-mgmt-provider\/dictionaries\/ja.dict.itop-service-mgmt-provider.php", + "2.x\/itop-service-mgmt-provider\/dictionaries\/ru.dict.itop-service-mgmt-provider.php", + "2.x\/itop-service-mgmt-provider\/dictionaries\/pl.dict.itop-service-mgmt-provider.php", + "2.x\/itop-service-mgmt-provider\/dictionaries\/fr.dict.itop-service-mgmt-provider.php", + "2.x\/itop-service-mgmt-provider\/dictionaries\/hu.dict.itop-service-mgmt-provider.php", + "2.x\/itop-service-mgmt-provider\/dictionaries\/en.dict.itop-service-mgmt-provider.php", + "2.x\/itop-service-mgmt-provider\/dictionaries\/it.dict.itop-service-mgmt-provider.php", + "2.x\/itop-service-mgmt-provider\/dictionaries\/cs.dict.itop-service-mgmt-provider.php", + "2.x\/itop-service-mgmt-provider\/dictionaries\/es_cr.dict.itop-service-mgmt-provider.php", + "2.x\/itop-service-mgmt-provider\/dictionaries\/pt_br.dict.itop-service-mgmt-provider.php", + "2.x\/itop-service-mgmt-provider\/dictionaries\/da.dict.itop-service-mgmt-provider.php", + "2.x\/itop-service-mgmt-provider\/dictionaries\/en_gb.dict.itop-service-mgmt-provider.php", + "2.x\/itop-service-mgmt-provider\/dictionaries\/nl.dict.itop-service-mgmt-provider.php" + ] + }, + "itop-service-mgmt\/3.3.0": { + "label": "Service Management", + "category": "business", + "dependencies": [ + "itop-tickets\/2.0.0" + ], + "mandatory": false, + "visible": true, + "installer": "ServiceMgmtInstaller", + "datamodel": [], + "data.struct": [], + "data.sample": [ + "data.sample.organizations.xml", + "data.sample.contracts.xml", + "data.sample.servicefamilies.xml", + "data.sample.services.xml", + "data.sample.serviceelements.xml", + "data.sample.sla.xml", + "data.sample.slt.xml", + "data.sample.sltsla.xml", + "data.sample.contractservice.xml", + "data.sample.deliverymodelcontact.xml" + ], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-service-mgmt\/module.itop-service-mgmt.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-service-mgmt", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-service-mgmt\/module.itop-service-mgmt.php", + "dictionary": [ + "2.x\/itop-service-mgmt\/dictionaries\/en_gb.dict.itop-service-mgmt.php", + "2.x\/itop-service-mgmt\/dictionaries\/hu.dict.itop-service-mgmt.php", + "2.x\/itop-service-mgmt\/dictionaries\/es_cr.dict.itop-service-mgmt.php", + "2.x\/itop-service-mgmt\/dictionaries\/nl.dict.itop-service-mgmt.php", + "2.x\/itop-service-mgmt\/dictionaries\/sk.dict.itop-service-mgmt.php", + "2.x\/itop-service-mgmt\/dictionaries\/it.dict.itop-service-mgmt.php", + "2.x\/itop-service-mgmt\/dictionaries\/da.dict.itop-service-mgmt.php", + "2.x\/itop-service-mgmt\/dictionaries\/zh_cn.dict.itop-service-mgmt.php", + "2.x\/itop-service-mgmt\/dictionaries\/pl.dict.itop-service-mgmt.php", + "2.x\/itop-service-mgmt\/dictionaries\/tr.dict.itop-service-mgmt.php", + "2.x\/itop-service-mgmt\/dictionaries\/en.dict.itop-service-mgmt.php", + "2.x\/itop-service-mgmt\/dictionaries\/cs.dict.itop-service-mgmt.php", + "2.x\/itop-service-mgmt\/dictionaries\/de.dict.itop-service-mgmt.php", + "2.x\/itop-service-mgmt\/dictionaries\/ja.dict.itop-service-mgmt.php", + "2.x\/itop-service-mgmt\/dictionaries\/ru.dict.itop-service-mgmt.php", + "2.x\/itop-service-mgmt\/dictionaries\/pt_br.dict.itop-service-mgmt.php", + "2.x\/itop-service-mgmt\/dictionaries\/fr.dict.itop-service-mgmt.php" + ] + }, + "itop-storage-mgmt\/3.3.0": { + "label": "Advanced Storage Management", + "category": "business", + "dependencies": [ + "itop-config-mgmt\/2.4.0" + ], + "mandatory": false, + "visible": true, + "installer": "StorageMgmtInstaller", + "datamodel": [], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-storage-mgmt\/module.itop-storage-mgmt.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-storage-mgmt", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-storage-mgmt\/module.itop-storage-mgmt.php", + "dictionary": [ + "2.x\/itop-storage-mgmt\/dictionaries\/en.dict.itop-storage-mgmt.php", + "2.x\/itop-storage-mgmt\/dictionaries\/cs.dict.itop-storage-mgmt.php", + "2.x\/itop-storage-mgmt\/dictionaries\/ja.dict.itop-storage-mgmt.php", + "2.x\/itop-storage-mgmt\/dictionaries\/da.dict.itop-storage-mgmt.php", + "2.x\/itop-storage-mgmt\/dictionaries\/pt_br.dict.itop-storage-mgmt.php", + "2.x\/itop-storage-mgmt\/dictionaries\/it.dict.itop-storage-mgmt.php", + "2.x\/itop-storage-mgmt\/dictionaries\/nl.dict.itop-storage-mgmt.php", + "2.x\/itop-storage-mgmt\/dictionaries\/fr.dict.itop-storage-mgmt.php", + "2.x\/itop-storage-mgmt\/dictionaries\/tr.dict.itop-storage-mgmt.php", + "2.x\/itop-storage-mgmt\/dictionaries\/es_cr.dict.itop-storage-mgmt.php", + "2.x\/itop-storage-mgmt\/dictionaries\/sk.dict.itop-storage-mgmt.php", + "2.x\/itop-storage-mgmt\/dictionaries\/zh_cn.dict.itop-storage-mgmt.php", + "2.x\/itop-storage-mgmt\/dictionaries\/en_gb.dict.itop-storage-mgmt.php", + "2.x\/itop-storage-mgmt\/dictionaries\/de.dict.itop-storage-mgmt.php", + "2.x\/itop-storage-mgmt\/dictionaries\/hu.dict.itop-storage-mgmt.php", + "2.x\/itop-storage-mgmt\/dictionaries\/pl.dict.itop-storage-mgmt.php", + "2.x\/itop-storage-mgmt\/dictionaries\/ru.dict.itop-storage-mgmt.php" + ] + }, + "itop-virtualization-mgmt\/3.3.0": { + "label": "Virtualization Management", + "category": "business", + "dependencies": [ + "itop-config-mgmt\/2.4.0" + ], + "mandatory": false, + "visible": true, + "datamodel": [], + "webservice": [], + "data.struct": [], + "data.sample": [ + "data.sample.farm.xml", + "data.sample.hypervisor.xml", + "data.sample.vm.xml", + "data.sample.dbserver.xml", + "data.sample.dbschema.xml", + "data.sample.webserver.xml", + "data.sample.webapp.xml", + "data.sample.applicationsolutionci.xml" + ], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-virtualization-mgmt\/module.itop-virtualization-mgmt.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-virtualization-mgmt", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-virtualization-mgmt\/module.itop-virtualization-mgmt.php", + "dictionary": [ + "2.x\/itop-virtualization-mgmt\/dictionaries\/de.dict.itop-virtualization-mgmt.php", + "2.x\/itop-virtualization-mgmt\/dictionaries\/en_gb.dict.itop-virtualization-mgmt.php", + "2.x\/itop-virtualization-mgmt\/dictionaries\/nl.dict.itop-virtualization-mgmt.php", + "2.x\/itop-virtualization-mgmt\/dictionaries\/ja.dict.itop-virtualization-mgmt.php", + "2.x\/itop-virtualization-mgmt\/dictionaries\/zh_cn.dict.itop-virtualization-mgmt.php", + "2.x\/itop-virtualization-mgmt\/dictionaries\/ru.dict.itop-virtualization-mgmt.php", + "2.x\/itop-virtualization-mgmt\/dictionaries\/sk.dict.itop-virtualization-mgmt.php", + "2.x\/itop-virtualization-mgmt\/dictionaries\/tr.dict.itop-virtualization-mgmt.php", + "2.x\/itop-virtualization-mgmt\/dictionaries\/fr.dict.itop-virtualization-mgmt.php", + "2.x\/itop-virtualization-mgmt\/dictionaries\/cs.dict.itop-virtualization-mgmt.php", + "2.x\/itop-virtualization-mgmt\/dictionaries\/da.dict.itop-virtualization-mgmt.php", + "2.x\/itop-virtualization-mgmt\/dictionaries\/hu.dict.itop-virtualization-mgmt.php", + "2.x\/itop-virtualization-mgmt\/dictionaries\/es_cr.dict.itop-virtualization-mgmt.php", + "2.x\/itop-virtualization-mgmt\/dictionaries\/en.dict.itop-virtualization-mgmt.php", + "2.x\/itop-virtualization-mgmt\/dictionaries\/pl.dict.itop-virtualization-mgmt.php", + "2.x\/itop-virtualization-mgmt\/dictionaries\/pt_br.dict.itop-virtualization-mgmt.php", + "2.x\/itop-virtualization-mgmt\/dictionaries\/it.dict.itop-virtualization-mgmt.php" + ] + }, + "itop-bridge-cmdb-services\/3.3.0": { + "label": "Bridge for CMDB and Services", + "category": "business", + "dependencies": [ + "itop-config-mgmt\/2.7.1", + "itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1" + ], + "mandatory": false, + "visible": false, + "auto_select": "SetupInfo::ModuleIsSelected(\"itop-config-mgmt\") && (SetupInfo::ModuleIsSelected(\"itop-service-mgmt\") || SetupInfo::ModuleIsSelected(\"itop-service-mgmt-provider\")) ", + "datamodel": [], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-cmdb-services\/module.itop-bridge-cmdb-services.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-cmdb-services", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-cmdb-services\/module.itop-bridge-cmdb-services.php", + "dictionary": [ + "2.x\/itop-bridge-cmdb-services\/dictionaries\/es_cr.dict.itop-bridge-cmdb-services.php", + "2.x\/itop-bridge-cmdb-services\/dictionaries\/cs.dict.itop-bridge-cmdb-services.php", + "2.x\/itop-bridge-cmdb-services\/dictionaries\/ja.dict.itop-bridge-cmdb-services.php", + "2.x\/itop-bridge-cmdb-services\/dictionaries\/hu.dict.itop-bridge-cmdb-services.php", + "2.x\/itop-bridge-cmdb-services\/dictionaries\/it.dict.itop-bridge-cmdb-services.php", + "2.x\/itop-bridge-cmdb-services\/dictionaries\/fr.dict.itop-bridge-cmdb-services.php", + "2.x\/itop-bridge-cmdb-services\/dictionaries\/pl.dict.itop-bridge-cmdb-services.php", + "2.x\/itop-bridge-cmdb-services\/dictionaries\/pt_br.dict.itop-bridge-cmdb-services.php", + "2.x\/itop-bridge-cmdb-services\/dictionaries\/nl.dict.itop-bridge-cmdb-services.php", + "2.x\/itop-bridge-cmdb-services\/dictionaries\/tr.dict.itop-bridge-cmdb-services.php", + "2.x\/itop-bridge-cmdb-services\/dictionaries\/da.dict.itop-bridge-cmdb-services.php", + "2.x\/itop-bridge-cmdb-services\/dictionaries\/ru.dict.itop-bridge-cmdb-services.php", + "2.x\/itop-bridge-cmdb-services\/dictionaries\/de.dict.itop-bridge-cmdb-services.php", + "2.x\/itop-bridge-cmdb-services\/dictionaries\/sk.dict.itop-bridge-cmdb-services.php", + "2.x\/itop-bridge-cmdb-services\/dictionaries\/zh_cn.dict.itop-bridge-cmdb-services.php", + "2.x\/itop-bridge-cmdb-services\/dictionaries\/en.dict.itop-bridge-cmdb-services.php", + "2.x\/itop-bridge-cmdb-services\/dictionaries\/en_gb.dict.itop-bridge-cmdb-services.php" + ] + }, + "itop-bridge-cmdb-ticket\/3.3.0": { + "label": "Bridge for CMDB and Ticket", + "category": "business", + "dependencies": [ + "itop-config-mgmt\/2.7.1", + "itop-tickets\/2.7.0" + ], + "mandatory": false, + "visible": false, + "auto_select": "SetupInfo::ModuleIsSelected(\"itop-config-mgmt\") && SetupInfo::ModuleIsSelected(\"itop-tickets\") ", + "datamodel": [], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-cmdb-ticket\/module.itop-bridge-cmdb-ticket.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-cmdb-ticket", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-cmdb-ticket\/module.itop-bridge-cmdb-ticket.php", + "dictionary": [ + "2.x\/itop-bridge-cmdb-ticket\/dictionaries\/it.dict.itop-bridge-cmdb-ticket.php", + "2.x\/itop-bridge-cmdb-ticket\/dictionaries\/ru.dict.itop-bridge-cmdb-ticket.php", + "2.x\/itop-bridge-cmdb-ticket\/dictionaries\/pt_br.dict.itop-bridge-cmdb-ticket.php", + "2.x\/itop-bridge-cmdb-ticket\/dictionaries\/zh_cn.dict.itop-bridge-cmdb-ticket.php", + "2.x\/itop-bridge-cmdb-ticket\/dictionaries\/en.dict.itop-bridge-cmdb-ticket.php", + "2.x\/itop-bridge-cmdb-ticket\/dictionaries\/ja.dict.itop-bridge-cmdb-ticket.php", + "2.x\/itop-bridge-cmdb-ticket\/dictionaries\/en_gb.dict.itop-bridge-cmdb-ticket.php", + "2.x\/itop-bridge-cmdb-ticket\/dictionaries\/hu.dict.itop-bridge-cmdb-ticket.php", + "2.x\/itop-bridge-cmdb-ticket\/dictionaries\/de.dict.itop-bridge-cmdb-ticket.php", + "2.x\/itop-bridge-cmdb-ticket\/dictionaries\/es_cr.dict.itop-bridge-cmdb-ticket.php", + "2.x\/itop-bridge-cmdb-ticket\/dictionaries\/tr.dict.itop-bridge-cmdb-ticket.php", + "2.x\/itop-bridge-cmdb-ticket\/dictionaries\/pl.dict.itop-bridge-cmdb-ticket.php", + "2.x\/itop-bridge-cmdb-ticket\/dictionaries\/fr.dict.itop-bridge-cmdb-ticket.php", + "2.x\/itop-bridge-cmdb-ticket\/dictionaries\/cs.dict.itop-bridge-cmdb-ticket.php", + "2.x\/itop-bridge-cmdb-ticket\/dictionaries\/da.dict.itop-bridge-cmdb-ticket.php", + "2.x\/itop-bridge-cmdb-ticket\/dictionaries\/nl.dict.itop-bridge-cmdb-ticket.php", + "2.x\/itop-bridge-cmdb-ticket\/dictionaries\/sk.dict.itop-bridge-cmdb-ticket.php" + ] + }, + "itop-bridge-datacenter-mgmt-services\/3.3.0": { + "label": "Bridge for CMDB Virtualization objects and Services", + "category": "business", + "dependencies": [ + "itop-config-mgmt\/2.7.1", + "itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1", + "itop-datacenter-mgmt\/3.1.0" + ], + "mandatory": false, + "visible": false, + "auto_select": "SetupInfo::ModuleIsSelected(\"itop-datacenter-mgmt\") && (SetupInfo::ModuleIsSelected(\"itop-service-mgmt\") || SetupInfo::ModuleIsSelected(\"itop-service-mgmt-provider\")) ", + "datamodel": [], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-datacenter-mgmt-services\/module.itop-bridge-datacenter-mgmt-services.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-datacenter-mgmt-services", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-datacenter-mgmt-services\/module.itop-bridge-datacenter-mgmt-services.php" + }, + "itop-bridge-endusers-devices-services\/3.3.0": { + "label": "Bridge for CMDB endusers objects and Services", + "category": "business", + "dependencies": [ + "itop-config-mgmt\/2.7.1", + "itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1", + "itop-endusers-devices\/3.1.0" + ], + "mandatory": false, + "visible": false, + "auto_select": "SetupInfo::ModuleIsSelected(\"itop-endusers-devices\") && (SetupInfo::ModuleIsSelected(\"itop-service-mgmt\") || SetupInfo::ModuleIsSelected(\"itop-service-mgmt-provider\")) ", + "datamodel": [], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-endusers-devices-services\/module.itop-bridge-endusers-devices-services.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-endusers-devices-services", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-endusers-devices-services\/module.itop-bridge-endusers-devices-services.php" + }, + "itop-bridge-storage-mgmt-services\/3.3.0": { + "label": "Bridge for CMDB Virtualization objects and Services", + "category": "business", + "dependencies": [ + "itop-config-mgmt\/2.7.1", + "itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1", + "itop-storage-mgmt\/3.1.0" + ], + "mandatory": false, + "visible": false, + "auto_select": "SetupInfo::ModuleIsSelected(\"itop-storage-mgmt\") && (SetupInfo::ModuleIsSelected(\"itop-service-mgmt\") || SetupInfo::ModuleIsSelected(\"itop-service-mgmt-provider\")) ", + "datamodel": [], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-storage-mgmt-services\/module.itop-bridge-storage-mgmt-services.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-storage-mgmt-services", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-storage-mgmt-services\/module.itop-bridge-storage-mgmt-services.php" + }, + "itop-bridge-virtualization-mgmt-services\/3.3.0": { + "label": "Bridge for CMDB Virtualization objects and Services", + "category": "business", + "dependencies": [ + "itop-config-mgmt\/2.7.1", + "itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1", + "itop-virtualization-mgmt\/3.1.0" + ], + "mandatory": false, + "visible": false, + "auto_select": "SetupInfo::ModuleIsSelected(\"itop-virtualization-mgmt\") && (SetupInfo::ModuleIsSelected(\"itop-service-mgmt\") || SetupInfo::ModuleIsSelected(\"itop-service-mgmt-provider\")) ", + "datamodel": [], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-virtualization-mgmt-services\/module.itop-bridge-virtualization-mgmt-services.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-virtualization-mgmt-services", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-virtualization-mgmt-services\/module.itop-bridge-virtualization-mgmt-services.php" + }, + "itop-bridge-virtualization-storage\/3.3.0": { + "label": "Links between virtualization and storage", + "category": "business", + "dependencies": [ + "itop-storage-mgmt\/2.2.0", + "itop-virtualization-mgmt\/2.2.0" + ], + "mandatory": false, + "visible": false, + "auto_select": "SetupInfo::ModuleIsSelected(\"itop-storage-mgmt\") && SetupInfo::ModuleIsSelected(\"itop-virtualization-mgmt\")", + "datamodel": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-virtualization-storage\/module.itop-bridge-virtualization-storage.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-virtualization-storage", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-bridge-virtualization-storage\/module.itop-bridge-virtualization-storage.php" + }, + "itop-change-mgmt-itil\/3.3.0": { + "label": "Change Management ITIL", + "category": "business", + "dependencies": [ + "itop-config-mgmt\/2.2.0", + "itop-tickets\/2.0.0" + ], + "mandatory": false, + "visible": true, + "datamodel": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-change-mgmt-itil\/module.itop-change-mgmt-itil.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-change-mgmt-itil", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-change-mgmt-itil\/module.itop-change-mgmt-itil.php", + "dictionary": [ + "2.x\/itop-change-mgmt-itil\/dictionaries\/hu.dict.itop-change-mgmt-itil.php", + "2.x\/itop-change-mgmt-itil\/dictionaries\/tr.dict.itop-change-mgmt-itil.php", + "2.x\/itop-change-mgmt-itil\/dictionaries\/fr.dict.itop-change-mgmt-itil.php", + "2.x\/itop-change-mgmt-itil\/dictionaries\/en.dict.itop-change-mgmt-itil.php", + "2.x\/itop-change-mgmt-itil\/dictionaries\/cs.dict.itop-change-mgmt-itil.php", + "2.x\/itop-change-mgmt-itil\/dictionaries\/da.dict.itop-change-mgmt-itil.php", + "2.x\/itop-change-mgmt-itil\/dictionaries\/sk.dict.itop-change-mgmt-itil.php", + "2.x\/itop-change-mgmt-itil\/dictionaries\/en_gb.dict.itop-change-mgmt-itil.php", + "2.x\/itop-change-mgmt-itil\/dictionaries\/nl.dict.itop-change-mgmt-itil.php", + "2.x\/itop-change-mgmt-itil\/dictionaries\/ja.dict.itop-change-mgmt-itil.php", + "2.x\/itop-change-mgmt-itil\/dictionaries\/es_cr.dict.itop-change-mgmt-itil.php", + "2.x\/itop-change-mgmt-itil\/dictionaries\/zh_cn.dict.itop-change-mgmt-itil.php", + "2.x\/itop-change-mgmt-itil\/dictionaries\/de.dict.itop-change-mgmt-itil.php", + "2.x\/itop-change-mgmt-itil\/dictionaries\/it.dict.itop-change-mgmt-itil.php", + "2.x\/itop-change-mgmt-itil\/dictionaries\/ru.dict.itop-change-mgmt-itil.php", + "2.x\/itop-change-mgmt-itil\/dictionaries\/pl.dict.itop-change-mgmt-itil.php", + "2.x\/itop-change-mgmt-itil\/dictionaries\/pt_br.dict.itop-change-mgmt-itil.php" + ] + }, + "itop-change-mgmt\/3.3.0": { + "label": "Change Management", + "category": "business", + "dependencies": [ + "itop-config-mgmt\/2.2.0", + "itop-tickets\/2.0.0" + ], + "mandatory": false, + "visible": true, + "installer": "ChangeManagementInstaller", + "datamodel": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-change-mgmt\/module.itop-change-mgmt.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-change-mgmt", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-change-mgmt\/module.itop-change-mgmt.php", + "dictionary": [ + "2.x\/itop-change-mgmt\/dictionaries\/zh_cn.dict.itop-change-mgmt.php", + "2.x\/itop-change-mgmt\/dictionaries\/en.dict.itop-change-mgmt.php", + "2.x\/itop-change-mgmt\/dictionaries\/tr.dict.itop-change-mgmt.php", + "2.x\/itop-change-mgmt\/dictionaries\/it.dict.itop-change-mgmt.php", + "2.x\/itop-change-mgmt\/dictionaries\/cs.dict.itop-change-mgmt.php", + "2.x\/itop-change-mgmt\/dictionaries\/hu.dict.itop-change-mgmt.php", + "2.x\/itop-change-mgmt\/dictionaries\/pl.dict.itop-change-mgmt.php", + "2.x\/itop-change-mgmt\/dictionaries\/en_gb.dict.itop-change-mgmt.php", + "2.x\/itop-change-mgmt\/dictionaries\/ja.dict.itop-change-mgmt.php", + "2.x\/itop-change-mgmt\/dictionaries\/da.dict.itop-change-mgmt.php", + "2.x\/itop-change-mgmt\/dictionaries\/es_cr.dict.itop-change-mgmt.php", + "2.x\/itop-change-mgmt\/dictionaries\/de.dict.itop-change-mgmt.php", + "2.x\/itop-change-mgmt\/dictionaries\/nl.dict.itop-change-mgmt.php", + "2.x\/itop-change-mgmt\/dictionaries\/sk.dict.itop-change-mgmt.php", + "2.x\/itop-change-mgmt\/dictionaries\/ru.dict.itop-change-mgmt.php", + "2.x\/itop-change-mgmt\/dictionaries\/pt_br.dict.itop-change-mgmt.php", + "2.x\/itop-change-mgmt\/dictionaries\/fr.dict.itop-change-mgmt.php" + ] + }, + "itop-full-itil\/3.3.0": { + "label": "Bridge - Request management ITIL + Incident management ITIL", + "category": "business", + "dependencies": [ + "itop-request-mgmt-itil\/2.3.0", + "itop-incident-mgmt-itil\/2.3.0" + ], + "mandatory": false, + "visible": false, + "auto_select": "SetupInfo::ModuleIsSelected(\"itop-request-mgmt-itil\") && SetupInfo::ModuleIsSelected(\"itop-incident-mgmt-itil\")", + "datamodel": [], + "webservice": [], + "data.struct": [], + "data.sample": [], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-full-itil\/module.itop-full-itil.php", + "itop_version": "1.0.2", + "root_dir": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-full-itil", + "module_file": "\/var\/www\/html\/iTopLegacy\/datamodels\/2.x\/itop-full-itil\/module.itop-full-itil.php" + } +} \ No newline at end of file diff --git a/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/installation.xml b/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/installation.xml new file mode 100644 index 0000000000..09f4c90cc2 --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/installation.xml @@ -0,0 +1,230 @@ + + + + + Configuration Management options + The options below allow you to configure the type of elements that are to be managed inside iTop.]]> + /images/icons/icons8-apps-tab.svg + + + itop-config-mgmt-core + Configuration Management Core + All the base objects that are mandatory in the iTop CMDB: Organizations, Locations, Teams, Persons, etc. + + combodo-backoffice-darkmoon-theme + combodo-backoffice-fullmoon-high-contrast-theme + combodo-backoffice-fullmoon-protanopia-deuteranopia-theme + combodo-backoffice-fullmoon-tritanopia-theme + combodo-db-tools + combodo-password-expiration + combodo-webhook-integration + itop-attachments + itop-backup + itop-config + itop-config-mgmt + itop-core-update + itop-files-information + itop-hub-connector + itop-oauth-client + itop-profiles-itil + itop-structure + itop-themes-compat + itop-tickets + itop-welcome-itil + combodo-my-account-user-info + authent-token + + true + + + itop-config-mgmt-datacenter + Data Center Devices + Manage Data Center devices such as Racks, Enclosures, PDUs, etc. + + itop-datacenter-mgmt + + true + + + itop-config-mgmt-end-user + End-User Devices + Manage devices related to end-users: PCs, Phones, Tablets, etc. + + itop-endusers-devices + + true + + + itop-config-mgmt-storage + Storage Devices + Manage storage devices such as NAS, SAN Switches, Tape Libraries and Tapes, etc. + + itop-storage-mgmt + + true + + + itop-config-mgmt-virtualization + Virtualization + Manage Hypervisors, Virtual Machines and Farms. + + itop-virtualization-mgmt + + true + + + + + Service Management options + Select the choice that best describes the relationships between the services and the IT infrastructure in your IT environment.]]> + /images/icons/icons8-services.svg + + + itop-service-mgmt-enterprise + Service Management for Enterprises + Select this option if the IT delivers services based on a shared infrastructure. For example if different organizations within your company subscribe to services (like Mail and Print services) delivered by a single shared backend. + + itop-service-mgmt + + true + + + itop-service-mgmt-service-provider + Service Management for Service Providers + Select this option if the IT manages the infrastructure of independent customers. This is the most flexible model, since the services can be delivered with a mix of shared and customer specific infrastructure devices. + + itop-service-mgmt-provider + + + + + + Tickets Management options + Select the type of tickets you want to use in order to respond to user requests and incidents.]]> + /images/icons/icons8-discussion-forum.svg + + + itop-ticket-mgmt-simple-ticket + Simple Ticket Management + Select this option to use one single type of tickets for all kind of requests. + + itop-request-mgmt + + true + + + + itop-ticket-mgmt-simple-ticket-enhanced-portal + Customer Portal + + + itop-portal + itop-portal-base + + true + + + + + + itop-ticket-mgmt-itil + ITIL Compliant Tickets Management + Select this option to have different types of ticket for managing user requests and incidents. Each type of ticket has a specific life cycle and specific fields + + + + itop-ticket-mgmt-itil-user-request + User Request Management + Manage User Request tickets in iTop + + itop-request-mgmt-itil + + + + itop-ticket-mgmt-itil-incident + Incident Management + Manage Incidents tickets in iTop + + itop-incident-mgmt-itil + + + + itop-ticket-mgmt-itil-enhanced-portal + Customer Portal + + + itop-portal + itop-portal-base + + true + + + + + + itop-ticket-mgmt-none + No Tickets Management + Don't manage incidents or user requests in iTop + + + + + + + Change Management options + Select the type of tickets you want to use in order to manage changes to the IT infrastructure.]]> + /images/icons/icons8-change.svg + + + itop-change-mgmt-simple + Simple Change Management + Select this option to use one type of ticket for all kind of changes. + + itop-change-mgmt + + true + + + itop-change-mgmt-itil + ITIL Change Management + Select this option to use Normal/Routine/Emergency change tickets. + + itop-change-mgmt-itil + + + + itop-change-mgmt-none + No Change Management + Don't manage changes in iTop + + + + + + + Additional ITIL tickets + Pick from the list below the additional ITIL processes that are to be implemented in iTop.]]> + /images/icons/icons8-important-book.svg + + + + itop-kown-error-mgmt + Known Errors Management and FAQ + Select this option to track "Known Errors" and FAQs in iTop. + + itop-faq-light + itop-knownerror-mgmt + + + + itop-problem-mgmt + Problem Management + Select this option to track "Problems" in iTop. + + itop-problem-mgmt + + + + + + \ No newline at end of file diff --git a/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/installation_choices_when_no_xml_file.json b/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/installation_choices_when_no_xml_file.json new file mode 100644 index 0000000000..2b455b857a --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/installation_choices_when_no_xml_file.json @@ -0,0 +1 @@ +{"itop-config-mgmt":{"label":"Configuration+Management+customized+for+Combodo+IT(CMDB)","value":"2.7.0"},"itop-icalendar-action":{"label":"Calendar+Invitations","value":"1.1.0"},"itop-fence":{"label":"iTop+Fence","value":"1.1.2"},"authent-ldap":{"label":"User+authentication+based+on+LDAP","value":"3.2.1"},"itop-faq-light":{"label":"Frequently+Asked+Questions+Database","value":"3.2.1"},"authent-local":{"label":"User+authentication+based+on+the+local+DB","value":"3.2.1"},"combodo-custom-hyperlinks":{"label":"Hyperlinks+configurator","value":"1.1.3"},"authent-token":{"label":"User+authentication+by+token","value":"2.2.1"},"itop-service-mgmt":{"label":"Service+Management+Customized+for+Combodo+IT(services,+SLAs,+contracts)","value":"2.7.0"},"combodo-impersonate":{"label":"Impersonate+user+for+support","value":"1.2.1"},"combodo-hybridauth":{"label":"oAuth\/OpenID+authentication","value":"1.2.4"},"combodo-login-page":{"label":"Combodo+login+page","value":"2.1.0"},"itop-core-update":{"label":"iTop+Core+Update","value":"3.2.1"},"itop-communications":{"label":"Communications+to+the+Customers","value":"1.3.4"},"itsm-designer-connector":{"label":"ITSM+Designer+Connector","value":"1.8.3"},"authent-external":{"label":"External+user+authentication","value":"3.2.1"},"itop-object-copier":{"label":"Object+copier","value":"1.4.5"},"combodo-backoffice-compact-themes":{"label":"Backoffice:+compact+themes","value":"1.0.1"},"data-localizer":{"label":"Data+localizer","value":"1.3.4"},"combodo-support-portal":{"label":"Combodo+Support+Portal","value":"3.0.1"},"combodo-calendar-view":{"label":"Calendar+View","value":"2.2.1"},"combodo-email-synchro":{"label":"Tickets+synchronization+via+e-mail","value":"3.8.2"},"combodo-webhook-integration":{"label":"Webhook+integrations","value":"1.4.1"},"combodo-notify-on-expiration":{"label":"Notify+on+expiration","value":"1.0.4"},"combodo-db-tools":{"label":"Database+maintenance+tools","value":"3.2.1"},"precanned-replies":{"label":"Helpdesk+Precanned+Replies","value":"1.4.0"},"combodo-dokuwiki-portal-brick":{"label":"Docuwiki+brick+(Portal)","value":"1.2.0"},"itop-rh-mgmt":{"label":"Human+Resource+Management","value":"2.7.0"},"itop-request-mgmt":{"label":"User+request+management+(Service+Desk)","value":"2.7.0"},"customer-survey":{"label":"Customer+Survey","value":"2.5.5"},"itop-standard-email-synchro":{"label":"Ticket+Creation+from+Emails+(Standard)","value":"3.8.2"},"itop-system-information":{"label":"System+information","value":"1.2.6"},"itop-sales-mgmt":{"label":"Sales+Management","value":"2.7.0"},"combodo-password-expiration":{"label":"Password+Expiration+Enforcement","value":"1.0.0"},"combodo-workflow-graphical-view":{"label":"Workflow+graphical+view","value":"1.1.3"},"combodo-itsm-master":{"label":"Data+master+for+the+ITSM+Designer","value":"2.7.0"},"combodo-email-tickets":{"label":"Tickets+Creation+from+Emails+for+Combodo","value":"2.7.0"},"itop-training-mgmt":{"label":"Training+Management","value":"2.7.0"},"precanned-replies-pro":{"label":"Helpdesk+Precanned+Replies+Extension","value":"1.2.0"},"combodo-fulltext-search":{"label":"Enhanced+global+search","value":"2.0.0"},"itop-request-template":{"label":"Customized+Request+Forms","value":"2.3.6"},"itop-rest-data-push":{"label":"Data+push+(based+on+standard+REST+services)","value":"1.0.2"},"combodo-kpi-logger":{"label":"KPI+logger","value":"1.0.3"},"itop-incident-mgmt":{"label":"Incident+Management","value":"2.7.0"},"combodo-my-account-user-info":{"label":"User+info+for+MyAccount+module","value":"1.0.0"},"email-reply":{"label":"Send+Ticket+Log+Updates+by+Email","value":"1.4.5"},"itop-attachments":{"label":"Tickets+Attachments","value":"3.2.1"},"itop-log-mgmt":{"label":"iTop+Log+management","value":"2.0.8"},"itop-ui-copypaste":{"label":"CopyPaste+UI+Component","value":"1.0.0"}} \ No newline at end of file diff --git a/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/priv_modules.json b/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/priv_modules.json new file mode 100644 index 0000000000..ac6f2b7cda --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/priv_modules.json @@ -0,0 +1,7218 @@ +[ + { + "0": "1", + "id": "1", + "1": "datamodel", + "name": "datamodel", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "{\"source_dir\":\"datamodels\\\/2.x\\\/\"}", + "comment": "{\"source_dir\":\"datamodels\\\/2.x\\\/\"}", + "5": "0", + "parent_id": "0", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "2", + "id": "2", + "1": "iTop", + "name": "iTop", + "2": "3.3.0-dev-svn", + "version": "3.3.0-dev-svn", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nBuilt on $WCNOW$", + "comment": "Done by the setup program\nBuilt on $WCNOW$", + "5": "0", + "parent_id": "0", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "3", + "id": "3", + "1": "authent-cas", + "name": "authent-cas", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nMandatory\nVisible (during the setup)", + "comment": "Done by the setup program\nMandatory\nVisible (during the setup)", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "4", + "id": "4", + "1": "authent-external", + "name": "authent-external", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nOptional\nVisible (during the setup)", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "5", + "id": "5", + "1": "authent-ldap", + "name": "authent-ldap", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nOptional\nVisible (during the setup)", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "6", + "id": "6", + "1": "authent-local", + "name": "authent-local", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nMandatory\nVisible (during the setup)", + "comment": "Done by the setup program\nMandatory\nVisible (during the setup)", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "7", + "id": "7", + "1": "combodo-backoffice-darkmoon-theme", + "name": "combodo-backoffice-darkmoon-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "8", + "id": "8", + "1": "combodo-backoffice-fullmoon-high-contrast-theme", + "name": "combodo-backoffice-fullmoon-high-contrast-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "9", + "id": "9", + "1": "combodo-backoffice-fullmoon-protanopia-deuteranopia-theme", + "name": "combodo-backoffice-fullmoon-protanopia-deuteranopia-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "10", + "id": "10", + "1": "combodo-backoffice-fullmoon-tritanopia-theme", + "name": "combodo-backoffice-fullmoon-tritanopia-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "11", + "id": "11", + "1": "itop-backup", + "name": "itop-backup", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "12", + "id": "12", + "1": "itop-config", + "name": "itop-config", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "13", + "id": "13", + "1": "itop-files-information", + "name": "itop-files-information", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "14", + "id": "14", + "1": "itop-portal-base", + "name": "itop-portal-base", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "15", + "id": "15", + "1": "itop-profiles-itil", + "name": "itop-profiles-itil", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "16", + "id": "16", + "1": "itop-sla-computation", + "name": "itop-sla-computation", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "17", + "id": "17", + "1": "itop-structure", + "name": "itop-structure", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "18", + "id": "18", + "1": "itop-welcome-itil", + "name": "itop-welcome-itil", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "19", + "id": "19", + "1": "itop-config-mgmt", + "name": "itop-config-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "20", + "id": "20", + "1": "itop-attachments", + "name": "itop-attachments", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nOptional\nVisible (during the setup)", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "21", + "id": "21", + "1": "itop-tickets", + "name": "itop-tickets", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "22", + "id": "22", + "1": "combodo-db-tools", + "name": "combodo-db-tools", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.0.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.0.0", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "23", + "id": "23", + "1": "itop-core-update", + "name": "itop-core-update", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-files-information\/2.7.0\nDepends on module: combodo-db-tools\/2.7.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-files-information\/2.7.0\nDepends on module: combodo-db-tools\/2.7.0", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "24", + "id": "24", + "1": "itop-hub-connector", + "name": "itop-hub-connector", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "25", + "id": "25", + "1": "itop-oauth-client", + "name": "itop-oauth-client", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-welcome-itil\/3.1.0,", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-welcome-itil\/3.1.0,", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "26", + "id": "26", + "1": "itop-themes-compat", + "name": "itop-themes-compat", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.1.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.1.0", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "27", + "id": "27", + "1": "itop-datacenter-mgmt", + "name": "itop-datacenter-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "28", + "id": "28", + "1": "itop-endusers-devices", + "name": "itop-endusers-devices", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "29", + "id": "29", + "1": "itop-storage-mgmt", + "name": "itop-storage-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "30", + "id": "30", + "1": "itop-virtualization-mgmt", + "name": "itop-virtualization-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "31", + "id": "31", + "1": "itop-bridge-cmdb-ticket", + "name": "itop-bridge-cmdb-ticket", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-tickets\/2.7.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-tickets\/2.7.0", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "32", + "id": "32", + "1": "itop-bridge-virtualization-storage", + "name": "itop-bridge-virtualization-storage", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-storage-mgmt\/2.2.0\nDepends on module: itop-virtualization-mgmt\/2.2.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-storage-mgmt\/2.2.0\nDepends on module: itop-virtualization-mgmt\/2.2.0", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "33", + "id": "33", + "1": "itop-service-mgmt", + "name": "itop-service-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.0.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.0.0", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "34", + "id": "34", + "1": "itop-bridge-cmdb-services", + "name": "itop-bridge-cmdb-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "35", + "id": "35", + "1": "itop-bridge-datacenter-mgmt-services", + "name": "itop-bridge-datacenter-mgmt-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-datacenter-mgmt\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-datacenter-mgmt\/3.1.0", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "36", + "id": "36", + "1": "itop-bridge-endusers-devices-services", + "name": "itop-bridge-endusers-devices-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-endusers-devices\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-endusers-devices\/3.1.0", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "37", + "id": "37", + "1": "itop-bridge-storage-mgmt-services", + "name": "itop-bridge-storage-mgmt-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-storage-mgmt\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-storage-mgmt\/3.1.0", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "38", + "id": "38", + "1": "itop-bridge-virtualization-mgmt-services", + "name": "itop-bridge-virtualization-mgmt-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-virtualization-mgmt\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-virtualization-mgmt\/3.1.0", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "39", + "id": "39", + "1": "itop-request-mgmt", + "name": "itop-request-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.4.0", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "40", + "id": "40", + "1": "itop-portal", + "name": "itop-portal", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-portal-base\/2.7.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-portal-base\/2.7.0", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "41", + "id": "41", + "1": "itop-change-mgmt", + "name": "itop-change-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:22:30", + "installed": "2025-11-10 10:22:30", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0\nDepends on module: itop-tickets\/2.0.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0\nDepends on module: itop-tickets\/2.0.0", + "5": "2", + "parent_id": "2", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "42", + "id": "42", + "1": "datamodel", + "name": "datamodel", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "{\"source_dir\":\"datamodels\\\/2.x\\\/\"}", + "comment": "{\"source_dir\":\"datamodels\\\/2.x\\\/\"}", + "5": "0", + "parent_id": "0", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "43", + "id": "43", + "1": "iTop", + "name": "iTop", + "2": "3.3.0-dev-svn", + "version": "3.3.0-dev-svn", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nBuilt on $WCNOW$", + "comment": "Done by the setup program\nBuilt on $WCNOW$", + "5": "0", + "parent_id": "0", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "44", + "id": "44", + "1": "authent-cas", + "name": "authent-cas", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nMandatory\nVisible (during the setup)", + "comment": "Done by the setup program\nMandatory\nVisible (during the setup)", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "45", + "id": "45", + "1": "authent-external", + "name": "authent-external", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nOptional\nVisible (during the setup)", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "46", + "id": "46", + "1": "authent-ldap", + "name": "authent-ldap", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nOptional\nVisible (during the setup)", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "47", + "id": "47", + "1": "authent-local", + "name": "authent-local", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nMandatory\nVisible (during the setup)", + "comment": "Done by the setup program\nMandatory\nVisible (during the setup)", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "48", + "id": "48", + "1": "combodo-backoffice-darkmoon-theme", + "name": "combodo-backoffice-darkmoon-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "49", + "id": "49", + "1": "combodo-backoffice-fullmoon-high-contrast-theme", + "name": "combodo-backoffice-fullmoon-high-contrast-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "50", + "id": "50", + "1": "combodo-backoffice-fullmoon-protanopia-deuteranopia-theme", + "name": "combodo-backoffice-fullmoon-protanopia-deuteranopia-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "51", + "id": "51", + "1": "combodo-backoffice-fullmoon-tritanopia-theme", + "name": "combodo-backoffice-fullmoon-tritanopia-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "52", + "id": "52", + "1": "itop-backup", + "name": "itop-backup", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "53", + "id": "53", + "1": "itop-config", + "name": "itop-config", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "54", + "id": "54", + "1": "itop-files-information", + "name": "itop-files-information", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "55", + "id": "55", + "1": "itop-portal-base", + "name": "itop-portal-base", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "56", + "id": "56", + "1": "itop-profiles-itil", + "name": "itop-profiles-itil", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "57", + "id": "57", + "1": "itop-sla-computation", + "name": "itop-sla-computation", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "58", + "id": "58", + "1": "itop-structure", + "name": "itop-structure", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "59", + "id": "59", + "1": "itop-welcome-itil", + "name": "itop-welcome-itil", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "60", + "id": "60", + "1": "itop-config-mgmt", + "name": "itop-config-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "61", + "id": "61", + "1": "itop-attachments", + "name": "itop-attachments", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nOptional\nVisible (during the setup)", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "62", + "id": "62", + "1": "itop-tickets", + "name": "itop-tickets", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "63", + "id": "63", + "1": "combodo-db-tools", + "name": "combodo-db-tools", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.0.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.0.0", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "64", + "id": "64", + "1": "itop-core-update", + "name": "itop-core-update", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-files-information\/2.7.0\nDepends on module: combodo-db-tools\/2.7.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-files-information\/2.7.0\nDepends on module: combodo-db-tools\/2.7.0", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "65", + "id": "65", + "1": "itop-hub-connector", + "name": "itop-hub-connector", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "66", + "id": "66", + "1": "itop-oauth-client", + "name": "itop-oauth-client", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-welcome-itil\/3.1.0,", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-welcome-itil\/3.1.0,", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "67", + "id": "67", + "1": "itop-themes-compat", + "name": "itop-themes-compat", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.1.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.1.0", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "68", + "id": "68", + "1": "itop-datacenter-mgmt", + "name": "itop-datacenter-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "69", + "id": "69", + "1": "itop-endusers-devices", + "name": "itop-endusers-devices", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "70", + "id": "70", + "1": "itop-storage-mgmt", + "name": "itop-storage-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "71", + "id": "71", + "1": "itop-virtualization-mgmt", + "name": "itop-virtualization-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "72", + "id": "72", + "1": "itop-bridge-cmdb-ticket", + "name": "itop-bridge-cmdb-ticket", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-tickets\/2.7.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-tickets\/2.7.0", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "73", + "id": "73", + "1": "itop-bridge-virtualization-storage", + "name": "itop-bridge-virtualization-storage", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-storage-mgmt\/2.2.0\nDepends on module: itop-virtualization-mgmt\/2.2.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-storage-mgmt\/2.2.0\nDepends on module: itop-virtualization-mgmt\/2.2.0", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "74", + "id": "74", + "1": "itop-service-mgmt", + "name": "itop-service-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.0.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.0.0", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "75", + "id": "75", + "1": "itop-bridge-cmdb-services", + "name": "itop-bridge-cmdb-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "76", + "id": "76", + "1": "itop-bridge-datacenter-mgmt-services", + "name": "itop-bridge-datacenter-mgmt-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-datacenter-mgmt\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-datacenter-mgmt\/3.1.0", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "77", + "id": "77", + "1": "itop-bridge-endusers-devices-services", + "name": "itop-bridge-endusers-devices-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-endusers-devices\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-endusers-devices\/3.1.0", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "78", + "id": "78", + "1": "itop-bridge-storage-mgmt-services", + "name": "itop-bridge-storage-mgmt-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-storage-mgmt\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-storage-mgmt\/3.1.0", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "79", + "id": "79", + "1": "itop-bridge-virtualization-mgmt-services", + "name": "itop-bridge-virtualization-mgmt-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-virtualization-mgmt\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-virtualization-mgmt\/3.1.0", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "80", + "id": "80", + "1": "itop-request-mgmt", + "name": "itop-request-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.4.0", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "81", + "id": "81", + "1": "itop-portal", + "name": "itop-portal", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-portal-base\/2.7.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-portal-base\/2.7.0", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "82", + "id": "82", + "1": "itop-change-mgmt", + "name": "itop-change-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:23:17", + "installed": "2025-11-10 10:23:17", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0\nDepends on module: itop-tickets\/2.0.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0\nDepends on module: itop-tickets\/2.0.0", + "5": "43", + "parent_id": "43", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "83", + "id": "83", + "1": "datamodel", + "name": "datamodel", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "{\"source_dir\":\"datamodels\\\/2.x\\\/\"}", + "comment": "{\"source_dir\":\"datamodels\\\/2.x\\\/\"}", + "5": "0", + "parent_id": "0", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "84", + "id": "84", + "1": "iTop", + "name": "iTop", + "2": "3.3.0-dev-svn", + "version": "3.3.0-dev-svn", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nBuilt on $WCNOW$", + "comment": "Done by the setup program\nBuilt on $WCNOW$", + "5": "0", + "parent_id": "0", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "85", + "id": "85", + "1": "authent-cas", + "name": "authent-cas", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nMandatory\nVisible (during the setup)", + "comment": "Done by the setup program\nMandatory\nVisible (during the setup)", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "86", + "id": "86", + "1": "authent-external", + "name": "authent-external", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nOptional\nVisible (during the setup)", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "87", + "id": "87", + "1": "authent-ldap", + "name": "authent-ldap", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nOptional\nVisible (during the setup)", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "88", + "id": "88", + "1": "authent-local", + "name": "authent-local", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nMandatory\nVisible (during the setup)", + "comment": "Done by the setup program\nMandatory\nVisible (during the setup)", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "89", + "id": "89", + "1": "combodo-backoffice-darkmoon-theme", + "name": "combodo-backoffice-darkmoon-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "90", + "id": "90", + "1": "combodo-backoffice-fullmoon-high-contrast-theme", + "name": "combodo-backoffice-fullmoon-high-contrast-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "91", + "id": "91", + "1": "combodo-backoffice-fullmoon-protanopia-deuteranopia-theme", + "name": "combodo-backoffice-fullmoon-protanopia-deuteranopia-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "92", + "id": "92", + "1": "combodo-backoffice-fullmoon-tritanopia-theme", + "name": "combodo-backoffice-fullmoon-tritanopia-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "93", + "id": "93", + "1": "itop-backup", + "name": "itop-backup", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "94", + "id": "94", + "1": "itop-config", + "name": "itop-config", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "95", + "id": "95", + "1": "itop-files-information", + "name": "itop-files-information", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "96", + "id": "96", + "1": "itop-portal-base", + "name": "itop-portal-base", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "97", + "id": "97", + "1": "itop-profiles-itil", + "name": "itop-profiles-itil", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "98", + "id": "98", + "1": "itop-sla-computation", + "name": "itop-sla-computation", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "99", + "id": "99", + "1": "itop-structure", + "name": "itop-structure", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "100", + "id": "100", + "1": "itop-welcome-itil", + "name": "itop-welcome-itil", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "101", + "id": "101", + "1": "itop-config-mgmt", + "name": "itop-config-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "102", + "id": "102", + "1": "itop-attachments", + "name": "itop-attachments", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nOptional\nVisible (during the setup)", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "103", + "id": "103", + "1": "itop-tickets", + "name": "itop-tickets", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "104", + "id": "104", + "1": "combodo-db-tools", + "name": "combodo-db-tools", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.0.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.0.0", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "105", + "id": "105", + "1": "itop-core-update", + "name": "itop-core-update", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-files-information\/2.7.0\nDepends on module: combodo-db-tools\/2.7.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-files-information\/2.7.0\nDepends on module: combodo-db-tools\/2.7.0", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "106", + "id": "106", + "1": "itop-hub-connector", + "name": "itop-hub-connector", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "107", + "id": "107", + "1": "itop-oauth-client", + "name": "itop-oauth-client", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-welcome-itil\/3.1.0,", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-welcome-itil\/3.1.0,", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "108", + "id": "108", + "1": "itop-themes-compat", + "name": "itop-themes-compat", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.1.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.1.0", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "109", + "id": "109", + "1": "itop-datacenter-mgmt", + "name": "itop-datacenter-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "110", + "id": "110", + "1": "itop-endusers-devices", + "name": "itop-endusers-devices", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "111", + "id": "111", + "1": "itop-storage-mgmt", + "name": "itop-storage-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "112", + "id": "112", + "1": "itop-virtualization-mgmt", + "name": "itop-virtualization-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "113", + "id": "113", + "1": "itop-bridge-cmdb-ticket", + "name": "itop-bridge-cmdb-ticket", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-tickets\/2.7.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-tickets\/2.7.0", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "114", + "id": "114", + "1": "itop-bridge-virtualization-storage", + "name": "itop-bridge-virtualization-storage", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-storage-mgmt\/2.2.0\nDepends on module: itop-virtualization-mgmt\/2.2.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-storage-mgmt\/2.2.0\nDepends on module: itop-virtualization-mgmt\/2.2.0", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "115", + "id": "115", + "1": "itop-service-mgmt", + "name": "itop-service-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.0.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.0.0", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "116", + "id": "116", + "1": "itop-bridge-cmdb-services", + "name": "itop-bridge-cmdb-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "117", + "id": "117", + "1": "itop-bridge-datacenter-mgmt-services", + "name": "itop-bridge-datacenter-mgmt-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-datacenter-mgmt\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-datacenter-mgmt\/3.1.0", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "118", + "id": "118", + "1": "itop-bridge-endusers-devices-services", + "name": "itop-bridge-endusers-devices-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-endusers-devices\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-endusers-devices\/3.1.0", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "119", + "id": "119", + "1": "itop-bridge-storage-mgmt-services", + "name": "itop-bridge-storage-mgmt-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-storage-mgmt\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-storage-mgmt\/3.1.0", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "120", + "id": "120", + "1": "itop-bridge-virtualization-mgmt-services", + "name": "itop-bridge-virtualization-mgmt-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-virtualization-mgmt\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-virtualization-mgmt\/3.1.0", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "121", + "id": "121", + "1": "itop-request-mgmt", + "name": "itop-request-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.4.0", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "122", + "id": "122", + "1": "itop-portal", + "name": "itop-portal", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-portal-base\/2.7.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-portal-base\/2.7.0", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "123", + "id": "123", + "1": "itop-change-mgmt", + "name": "itop-change-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:25:21", + "installed": "2025-11-10 10:25:21", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0\nDepends on module: itop-tickets\/2.0.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0\nDepends on module: itop-tickets\/2.0.0", + "5": "84", + "parent_id": "84", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "124", + "id": "124", + "1": "datamodel", + "name": "datamodel", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "{\"source_dir\":\"datamodels\\\/2.x\\\/\"}", + "comment": "{\"source_dir\":\"datamodels\\\/2.x\\\/\"}", + "5": "0", + "parent_id": "0", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "125", + "id": "125", + "1": "iTop", + "name": "iTop", + "2": "3.3.0-dev-svn", + "version": "3.3.0-dev-svn", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nBuilt on $WCNOW$", + "comment": "Done by the setup program\nBuilt on $WCNOW$", + "5": "0", + "parent_id": "0", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "126", + "id": "126", + "1": "authent-cas", + "name": "authent-cas", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nMandatory\nVisible (during the setup)", + "comment": "Done by the setup program\nMandatory\nVisible (during the setup)", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "127", + "id": "127", + "1": "authent-external", + "name": "authent-external", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nOptional\nVisible (during the setup)", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "128", + "id": "128", + "1": "authent-ldap", + "name": "authent-ldap", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nOptional\nVisible (during the setup)", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "129", + "id": "129", + "1": "authent-local", + "name": "authent-local", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nMandatory\nVisible (during the setup)", + "comment": "Done by the setup program\nMandatory\nVisible (during the setup)", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "130", + "id": "130", + "1": "combodo-backoffice-darkmoon-theme", + "name": "combodo-backoffice-darkmoon-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "131", + "id": "131", + "1": "combodo-backoffice-fullmoon-high-contrast-theme", + "name": "combodo-backoffice-fullmoon-high-contrast-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "132", + "id": "132", + "1": "combodo-backoffice-fullmoon-protanopia-deuteranopia-theme", + "name": "combodo-backoffice-fullmoon-protanopia-deuteranopia-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "133", + "id": "133", + "1": "combodo-backoffice-fullmoon-tritanopia-theme", + "name": "combodo-backoffice-fullmoon-tritanopia-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "134", + "id": "134", + "1": "itop-backup", + "name": "itop-backup", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "135", + "id": "135", + "1": "itop-config", + "name": "itop-config", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "136", + "id": "136", + "1": "itop-files-information", + "name": "itop-files-information", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "137", + "id": "137", + "1": "itop-portal-base", + "name": "itop-portal-base", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "138", + "id": "138", + "1": "itop-profiles-itil", + "name": "itop-profiles-itil", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "139", + "id": "139", + "1": "itop-sla-computation", + "name": "itop-sla-computation", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "140", + "id": "140", + "1": "itop-structure", + "name": "itop-structure", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "141", + "id": "141", + "1": "itop-welcome-itil", + "name": "itop-welcome-itil", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "142", + "id": "142", + "1": "itop-config-mgmt", + "name": "itop-config-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "143", + "id": "143", + "1": "itop-attachments", + "name": "itop-attachments", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nOptional\nVisible (during the setup)", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "144", + "id": "144", + "1": "itop-tickets", + "name": "itop-tickets", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "145", + "id": "145", + "1": "combodo-db-tools", + "name": "combodo-db-tools", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.0.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.0.0", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "146", + "id": "146", + "1": "itop-core-update", + "name": "itop-core-update", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-files-information\/2.7.0\nDepends on module: combodo-db-tools\/2.7.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-files-information\/2.7.0\nDepends on module: combodo-db-tools\/2.7.0", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "147", + "id": "147", + "1": "itop-hub-connector", + "name": "itop-hub-connector", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "148", + "id": "148", + "1": "itop-oauth-client", + "name": "itop-oauth-client", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-welcome-itil\/3.1.0,", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-welcome-itil\/3.1.0,", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "149", + "id": "149", + "1": "itop-themes-compat", + "name": "itop-themes-compat", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.1.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.1.0", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "150", + "id": "150", + "1": "itop-datacenter-mgmt", + "name": "itop-datacenter-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "151", + "id": "151", + "1": "itop-endusers-devices", + "name": "itop-endusers-devices", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "152", + "id": "152", + "1": "itop-storage-mgmt", + "name": "itop-storage-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "153", + "id": "153", + "1": "itop-virtualization-mgmt", + "name": "itop-virtualization-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "154", + "id": "154", + "1": "itop-bridge-cmdb-ticket", + "name": "itop-bridge-cmdb-ticket", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-tickets\/2.7.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-tickets\/2.7.0", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "155", + "id": "155", + "1": "itop-bridge-virtualization-storage", + "name": "itop-bridge-virtualization-storage", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-storage-mgmt\/2.2.0\nDepends on module: itop-virtualization-mgmt\/2.2.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-storage-mgmt\/2.2.0\nDepends on module: itop-virtualization-mgmt\/2.2.0", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "156", + "id": "156", + "1": "itop-service-mgmt", + "name": "itop-service-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.0.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.0.0", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "157", + "id": "157", + "1": "itop-bridge-cmdb-services", + "name": "itop-bridge-cmdb-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "158", + "id": "158", + "1": "itop-bridge-datacenter-mgmt-services", + "name": "itop-bridge-datacenter-mgmt-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-datacenter-mgmt\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-datacenter-mgmt\/3.1.0", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "159", + "id": "159", + "1": "itop-bridge-endusers-devices-services", + "name": "itop-bridge-endusers-devices-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-endusers-devices\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-endusers-devices\/3.1.0", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "160", + "id": "160", + "1": "itop-bridge-storage-mgmt-services", + "name": "itop-bridge-storage-mgmt-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-storage-mgmt\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-storage-mgmt\/3.1.0", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "161", + "id": "161", + "1": "itop-bridge-virtualization-mgmt-services", + "name": "itop-bridge-virtualization-mgmt-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-virtualization-mgmt\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-virtualization-mgmt\/3.1.0", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "162", + "id": "162", + "1": "itop-request-mgmt", + "name": "itop-request-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.4.0", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "163", + "id": "163", + "1": "itop-portal", + "name": "itop-portal", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-portal-base\/2.7.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-portal-base\/2.7.0", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "164", + "id": "164", + "1": "itop-change-mgmt", + "name": "itop-change-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:35:39", + "installed": "2025-11-10 10:35:39", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0\nDepends on module: itop-tickets\/2.0.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0\nDepends on module: itop-tickets\/2.0.0", + "5": "125", + "parent_id": "125", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "165", + "id": "165", + "1": "datamodel", + "name": "datamodel", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "{\"source_dir\":\"datamodels\\\/2.x\\\/\"}", + "comment": "{\"source_dir\":\"datamodels\\\/2.x\\\/\"}", + "5": "0", + "parent_id": "0", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "166", + "id": "166", + "1": "iTop", + "name": "iTop", + "2": "3.3.0-dev-svn", + "version": "3.3.0-dev-svn", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nBuilt on $WCNOW$", + "comment": "Done by the setup program\nBuilt on $WCNOW$", + "5": "0", + "parent_id": "0", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "167", + "id": "167", + "1": "authent-cas", + "name": "authent-cas", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nMandatory\nVisible (during the setup)", + "comment": "Done by the setup program\nMandatory\nVisible (during the setup)", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "168", + "id": "168", + "1": "authent-external", + "name": "authent-external", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nOptional\nVisible (during the setup)", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "169", + "id": "169", + "1": "authent-ldap", + "name": "authent-ldap", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nOptional\nVisible (during the setup)", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "170", + "id": "170", + "1": "authent-local", + "name": "authent-local", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nMandatory\nVisible (during the setup)", + "comment": "Done by the setup program\nMandatory\nVisible (during the setup)", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "171", + "id": "171", + "1": "combodo-backoffice-darkmoon-theme", + "name": "combodo-backoffice-darkmoon-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "172", + "id": "172", + "1": "combodo-backoffice-fullmoon-high-contrast-theme", + "name": "combodo-backoffice-fullmoon-high-contrast-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "173", + "id": "173", + "1": "combodo-backoffice-fullmoon-protanopia-deuteranopia-theme", + "name": "combodo-backoffice-fullmoon-protanopia-deuteranopia-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "174", + "id": "174", + "1": "combodo-backoffice-fullmoon-tritanopia-theme", + "name": "combodo-backoffice-fullmoon-tritanopia-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "175", + "id": "175", + "1": "itop-backup", + "name": "itop-backup", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "176", + "id": "176", + "1": "itop-config", + "name": "itop-config", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "177", + "id": "177", + "1": "itop-files-information", + "name": "itop-files-information", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "178", + "id": "178", + "1": "itop-portal-base", + "name": "itop-portal-base", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "179", + "id": "179", + "1": "itop-profiles-itil", + "name": "itop-profiles-itil", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "180", + "id": "180", + "1": "itop-sla-computation", + "name": "itop-sla-computation", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "181", + "id": "181", + "1": "itop-structure", + "name": "itop-structure", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "182", + "id": "182", + "1": "itop-welcome-itil", + "name": "itop-welcome-itil", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "183", + "id": "183", + "1": "itop-config-mgmt", + "name": "itop-config-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "184", + "id": "184", + "1": "itop-attachments", + "name": "itop-attachments", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nOptional\nVisible (during the setup)", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "185", + "id": "185", + "1": "itop-tickets", + "name": "itop-tickets", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "186", + "id": "186", + "1": "combodo-db-tools", + "name": "combodo-db-tools", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.0.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.0.0", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "187", + "id": "187", + "1": "itop-core-update", + "name": "itop-core-update", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-files-information\/2.7.0\nDepends on module: combodo-db-tools\/2.7.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-files-information\/2.7.0\nDepends on module: combodo-db-tools\/2.7.0", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "188", + "id": "188", + "1": "itop-hub-connector", + "name": "itop-hub-connector", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "189", + "id": "189", + "1": "itop-oauth-client", + "name": "itop-oauth-client", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-welcome-itil\/3.1.0,", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-welcome-itil\/3.1.0,", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "190", + "id": "190", + "1": "itop-themes-compat", + "name": "itop-themes-compat", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.1.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.1.0", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "191", + "id": "191", + "1": "itop-datacenter-mgmt", + "name": "itop-datacenter-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "192", + "id": "192", + "1": "itop-endusers-devices", + "name": "itop-endusers-devices", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "193", + "id": "193", + "1": "itop-storage-mgmt", + "name": "itop-storage-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "194", + "id": "194", + "1": "itop-virtualization-mgmt", + "name": "itop-virtualization-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "195", + "id": "195", + "1": "itop-bridge-cmdb-ticket", + "name": "itop-bridge-cmdb-ticket", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-tickets\/2.7.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-tickets\/2.7.0", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "196", + "id": "196", + "1": "itop-bridge-virtualization-storage", + "name": "itop-bridge-virtualization-storage", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-storage-mgmt\/2.2.0\nDepends on module: itop-virtualization-mgmt\/2.2.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-storage-mgmt\/2.2.0\nDepends on module: itop-virtualization-mgmt\/2.2.0", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "197", + "id": "197", + "1": "itop-service-mgmt", + "name": "itop-service-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.0.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.0.0", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "198", + "id": "198", + "1": "itop-bridge-cmdb-services", + "name": "itop-bridge-cmdb-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "199", + "id": "199", + "1": "itop-bridge-datacenter-mgmt-services", + "name": "itop-bridge-datacenter-mgmt-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-datacenter-mgmt\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-datacenter-mgmt\/3.1.0", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "200", + "id": "200", + "1": "itop-bridge-endusers-devices-services", + "name": "itop-bridge-endusers-devices-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-endusers-devices\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-endusers-devices\/3.1.0", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "201", + "id": "201", + "1": "itop-bridge-storage-mgmt-services", + "name": "itop-bridge-storage-mgmt-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-storage-mgmt\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-storage-mgmt\/3.1.0", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "202", + "id": "202", + "1": "itop-bridge-virtualization-mgmt-services", + "name": "itop-bridge-virtualization-mgmt-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-virtualization-mgmt\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-virtualization-mgmt\/3.1.0", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "203", + "id": "203", + "1": "itop-request-mgmt", + "name": "itop-request-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.4.0", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "204", + "id": "204", + "1": "itop-portal", + "name": "itop-portal", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-portal-base\/2.7.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-portal-base\/2.7.0", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "205", + "id": "205", + "1": "itop-change-mgmt", + "name": "itop-change-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:40:45", + "installed": "2025-11-10 10:40:45", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0\nDepends on module: itop-tickets\/2.0.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0\nDepends on module: itop-tickets\/2.0.0", + "5": "166", + "parent_id": "166", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "206", + "id": "206", + "1": "datamodel", + "name": "datamodel", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "{\"source_dir\":\"datamodels\\\/2.x\\\/\"}", + "comment": "{\"source_dir\":\"datamodels\\\/2.x\\\/\"}", + "5": "0", + "parent_id": "0", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "207", + "id": "207", + "1": "iTop", + "name": "iTop", + "2": "3.3.0-dev-svn", + "version": "3.3.0-dev-svn", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nBuilt on $WCNOW$", + "comment": "Done by the setup program\nBuilt on $WCNOW$", + "5": "0", + "parent_id": "0", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "208", + "id": "208", + "1": "authent-cas", + "name": "authent-cas", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nMandatory\nVisible (during the setup)", + "comment": "Done by the setup program\nMandatory\nVisible (during the setup)", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "209", + "id": "209", + "1": "authent-external", + "name": "authent-external", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nOptional\nVisible (during the setup)", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "210", + "id": "210", + "1": "authent-ldap", + "name": "authent-ldap", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nOptional\nVisible (during the setup)", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "211", + "id": "211", + "1": "authent-local", + "name": "authent-local", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nMandatory\nVisible (during the setup)", + "comment": "Done by the setup program\nMandatory\nVisible (during the setup)", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "212", + "id": "212", + "1": "combodo-backoffice-darkmoon-theme", + "name": "combodo-backoffice-darkmoon-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "213", + "id": "213", + "1": "combodo-backoffice-fullmoon-high-contrast-theme", + "name": "combodo-backoffice-fullmoon-high-contrast-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "214", + "id": "214", + "1": "combodo-backoffice-fullmoon-protanopia-deuteranopia-theme", + "name": "combodo-backoffice-fullmoon-protanopia-deuteranopia-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "215", + "id": "215", + "1": "combodo-backoffice-fullmoon-tritanopia-theme", + "name": "combodo-backoffice-fullmoon-tritanopia-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "216", + "id": "216", + "1": "itop-backup", + "name": "itop-backup", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "217", + "id": "217", + "1": "itop-config", + "name": "itop-config", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "218", + "id": "218", + "1": "itop-files-information", + "name": "itop-files-information", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "219", + "id": "219", + "1": "itop-portal-base", + "name": "itop-portal-base", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "220", + "id": "220", + "1": "itop-profiles-itil", + "name": "itop-profiles-itil", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "221", + "id": "221", + "1": "itop-sla-computation", + "name": "itop-sla-computation", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "222", + "id": "222", + "1": "itop-structure", + "name": "itop-structure", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "223", + "id": "223", + "1": "itop-welcome-itil", + "name": "itop-welcome-itil", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "224", + "id": "224", + "1": "itop-config-mgmt", + "name": "itop-config-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "225", + "id": "225", + "1": "itop-attachments", + "name": "itop-attachments", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nOptional\nVisible (during the setup)", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "226", + "id": "226", + "1": "itop-tickets", + "name": "itop-tickets", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "227", + "id": "227", + "1": "combodo-db-tools", + "name": "combodo-db-tools", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.0.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.0.0", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "228", + "id": "228", + "1": "itop-core-update", + "name": "itop-core-update", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-files-information\/2.7.0\nDepends on module: combodo-db-tools\/2.7.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-files-information\/2.7.0\nDepends on module: combodo-db-tools\/2.7.0", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "229", + "id": "229", + "1": "itop-hub-connector", + "name": "itop-hub-connector", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "230", + "id": "230", + "1": "itop-oauth-client", + "name": "itop-oauth-client", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-welcome-itil\/3.1.0,", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-welcome-itil\/3.1.0,", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "231", + "id": "231", + "1": "itop-themes-compat", + "name": "itop-themes-compat", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.1.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.1.0", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "232", + "id": "232", + "1": "itop-datacenter-mgmt", + "name": "itop-datacenter-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "233", + "id": "233", + "1": "itop-endusers-devices", + "name": "itop-endusers-devices", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "234", + "id": "234", + "1": "itop-storage-mgmt", + "name": "itop-storage-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "235", + "id": "235", + "1": "itop-virtualization-mgmt", + "name": "itop-virtualization-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "236", + "id": "236", + "1": "itop-bridge-cmdb-ticket", + "name": "itop-bridge-cmdb-ticket", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-tickets\/2.7.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-tickets\/2.7.0", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "237", + "id": "237", + "1": "itop-bridge-virtualization-storage", + "name": "itop-bridge-virtualization-storage", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-storage-mgmt\/2.2.0\nDepends on module: itop-virtualization-mgmt\/2.2.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-storage-mgmt\/2.2.0\nDepends on module: itop-virtualization-mgmt\/2.2.0", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "238", + "id": "238", + "1": "itop-service-mgmt", + "name": "itop-service-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.0.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.0.0", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "239", + "id": "239", + "1": "itop-bridge-cmdb-services", + "name": "itop-bridge-cmdb-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "240", + "id": "240", + "1": "itop-bridge-datacenter-mgmt-services", + "name": "itop-bridge-datacenter-mgmt-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-datacenter-mgmt\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-datacenter-mgmt\/3.1.0", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "241", + "id": "241", + "1": "itop-bridge-endusers-devices-services", + "name": "itop-bridge-endusers-devices-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-endusers-devices\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-endusers-devices\/3.1.0", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "242", + "id": "242", + "1": "itop-bridge-storage-mgmt-services", + "name": "itop-bridge-storage-mgmt-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-storage-mgmt\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-storage-mgmt\/3.1.0", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "243", + "id": "243", + "1": "itop-bridge-virtualization-mgmt-services", + "name": "itop-bridge-virtualization-mgmt-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-virtualization-mgmt\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-virtualization-mgmt\/3.1.0", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "244", + "id": "244", + "1": "itop-request-mgmt", + "name": "itop-request-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.4.0", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "245", + "id": "245", + "1": "itop-portal", + "name": "itop-portal", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-portal-base\/2.7.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-portal-base\/2.7.0", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "246", + "id": "246", + "1": "itop-change-mgmt", + "name": "itop-change-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 10:43:58", + "installed": "2025-11-10 10:43:58", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0\nDepends on module: itop-tickets\/2.0.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0\nDepends on module: itop-tickets\/2.0.0", + "5": "207", + "parent_id": "207", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "247", + "id": "247", + "1": "datamodel", + "name": "datamodel", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "{\"source_dir\":\"datamodels\\\/2.x\\\/\"}", + "comment": "{\"source_dir\":\"datamodels\\\/2.x\\\/\"}", + "5": "0", + "parent_id": "0", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "248", + "id": "248", + "1": "iTop", + "name": "iTop", + "2": "3.3.0-dev-svn", + "version": "3.3.0-dev-svn", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nBuilt on $WCNOW$", + "comment": "Done by the setup program\nBuilt on $WCNOW$", + "5": "0", + "parent_id": "0", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "249", + "id": "249", + "1": "authent-cas", + "name": "authent-cas", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nMandatory\nVisible (during the setup)", + "comment": "Done by the setup program\nMandatory\nVisible (during the setup)", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "250", + "id": "250", + "1": "authent-external", + "name": "authent-external", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nOptional\nVisible (during the setup)", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "251", + "id": "251", + "1": "authent-ldap", + "name": "authent-ldap", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nOptional\nVisible (during the setup)", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "252", + "id": "252", + "1": "authent-local", + "name": "authent-local", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nMandatory\nVisible (during the setup)", + "comment": "Done by the setup program\nMandatory\nVisible (during the setup)", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "253", + "id": "253", + "1": "combodo-backoffice-darkmoon-theme", + "name": "combodo-backoffice-darkmoon-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "254", + "id": "254", + "1": "combodo-backoffice-fullmoon-high-contrast-theme", + "name": "combodo-backoffice-fullmoon-high-contrast-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "255", + "id": "255", + "1": "combodo-backoffice-fullmoon-protanopia-deuteranopia-theme", + "name": "combodo-backoffice-fullmoon-protanopia-deuteranopia-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "256", + "id": "256", + "1": "combodo-backoffice-fullmoon-tritanopia-theme", + "name": "combodo-backoffice-fullmoon-tritanopia-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "257", + "id": "257", + "1": "itop-backup", + "name": "itop-backup", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "258", + "id": "258", + "1": "itop-config", + "name": "itop-config", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "259", + "id": "259", + "1": "itop-files-information", + "name": "itop-files-information", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "260", + "id": "260", + "1": "itop-portal-base", + "name": "itop-portal-base", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "261", + "id": "261", + "1": "itop-profiles-itil", + "name": "itop-profiles-itil", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "262", + "id": "262", + "1": "itop-sla-computation", + "name": "itop-sla-computation", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "263", + "id": "263", + "1": "itop-structure", + "name": "itop-structure", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "264", + "id": "264", + "1": "itop-welcome-itil", + "name": "itop-welcome-itil", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "265", + "id": "265", + "1": "itop-config-mgmt", + "name": "itop-config-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "266", + "id": "266", + "1": "itop-attachments", + "name": "itop-attachments", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nOptional\nVisible (during the setup)", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "267", + "id": "267", + "1": "itop-tickets", + "name": "itop-tickets", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "268", + "id": "268", + "1": "combodo-db-tools", + "name": "combodo-db-tools", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.0.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.0.0", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "269", + "id": "269", + "1": "itop-core-update", + "name": "itop-core-update", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-files-information\/2.7.0\nDepends on module: combodo-db-tools\/2.7.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-files-information\/2.7.0\nDepends on module: combodo-db-tools\/2.7.0", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "270", + "id": "270", + "1": "itop-hub-connector", + "name": "itop-hub-connector", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "271", + "id": "271", + "1": "itop-oauth-client", + "name": "itop-oauth-client", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-welcome-itil\/3.1.0,", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-welcome-itil\/3.1.0,", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "272", + "id": "272", + "1": "itop-themes-compat", + "name": "itop-themes-compat", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.1.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.1.0", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "273", + "id": "273", + "1": "itop-datacenter-mgmt", + "name": "itop-datacenter-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "274", + "id": "274", + "1": "itop-endusers-devices", + "name": "itop-endusers-devices", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "275", + "id": "275", + "1": "itop-storage-mgmt", + "name": "itop-storage-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "276", + "id": "276", + "1": "itop-virtualization-mgmt", + "name": "itop-virtualization-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "277", + "id": "277", + "1": "itop-bridge-cmdb-ticket", + "name": "itop-bridge-cmdb-ticket", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-tickets\/2.7.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-tickets\/2.7.0", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "278", + "id": "278", + "1": "itop-bridge-virtualization-storage", + "name": "itop-bridge-virtualization-storage", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-storage-mgmt\/2.2.0\nDepends on module: itop-virtualization-mgmt\/2.2.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-storage-mgmt\/2.2.0\nDepends on module: itop-virtualization-mgmt\/2.2.0", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "279", + "id": "279", + "1": "itop-service-mgmt", + "name": "itop-service-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.0.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.0.0", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "280", + "id": "280", + "1": "itop-bridge-cmdb-services", + "name": "itop-bridge-cmdb-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "281", + "id": "281", + "1": "itop-bridge-datacenter-mgmt-services", + "name": "itop-bridge-datacenter-mgmt-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-datacenter-mgmt\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-datacenter-mgmt\/3.1.0", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "282", + "id": "282", + "1": "itop-bridge-endusers-devices-services", + "name": "itop-bridge-endusers-devices-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-endusers-devices\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-endusers-devices\/3.1.0", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "283", + "id": "283", + "1": "itop-bridge-storage-mgmt-services", + "name": "itop-bridge-storage-mgmt-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-storage-mgmt\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-storage-mgmt\/3.1.0", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "284", + "id": "284", + "1": "itop-bridge-virtualization-mgmt-services", + "name": "itop-bridge-virtualization-mgmt-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-virtualization-mgmt\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-virtualization-mgmt\/3.1.0", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "285", + "id": "285", + "1": "itop-request-mgmt", + "name": "itop-request-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.4.0", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "286", + "id": "286", + "1": "itop-portal", + "name": "itop-portal", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-portal-base\/2.7.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-portal-base\/2.7.0", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "287", + "id": "287", + "1": "itop-change-mgmt", + "name": "itop-change-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:43:55", + "installed": "2025-11-10 11:43:55", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0\nDepends on module: itop-tickets\/2.0.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0\nDepends on module: itop-tickets\/2.0.0", + "5": "248", + "parent_id": "248", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "288", + "id": "288", + "1": "datamodel", + "name": "datamodel", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "{\"source_dir\":\"datamodels\\\/2.x\\\/\"}", + "comment": "{\"source_dir\":\"datamodels\\\/2.x\\\/\"}", + "5": "0", + "parent_id": "0", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "289", + "id": "289", + "1": "iTop", + "name": "iTop", + "2": "3.3.0-dev-svn", + "version": "3.3.0-dev-svn", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nBuilt on $WCNOW$", + "comment": "Done by the setup program\nBuilt on $WCNOW$", + "5": "0", + "parent_id": "0", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "290", + "id": "290", + "1": "authent-cas", + "name": "authent-cas", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nMandatory\nVisible (during the setup)", + "comment": "Done by the setup program\nMandatory\nVisible (during the setup)", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "291", + "id": "291", + "1": "authent-external", + "name": "authent-external", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nOptional\nVisible (during the setup)", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "292", + "id": "292", + "1": "authent-ldap", + "name": "authent-ldap", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nOptional\nVisible (during the setup)", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "293", + "id": "293", + "1": "authent-local", + "name": "authent-local", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nMandatory\nVisible (during the setup)", + "comment": "Done by the setup program\nMandatory\nVisible (during the setup)", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "294", + "id": "294", + "1": "combodo-backoffice-darkmoon-theme", + "name": "combodo-backoffice-darkmoon-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "295", + "id": "295", + "1": "combodo-backoffice-fullmoon-high-contrast-theme", + "name": "combodo-backoffice-fullmoon-high-contrast-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "296", + "id": "296", + "1": "combodo-backoffice-fullmoon-protanopia-deuteranopia-theme", + "name": "combodo-backoffice-fullmoon-protanopia-deuteranopia-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "297", + "id": "297", + "1": "combodo-backoffice-fullmoon-tritanopia-theme", + "name": "combodo-backoffice-fullmoon-tritanopia-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "298", + "id": "298", + "1": "itop-backup", + "name": "itop-backup", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "299", + "id": "299", + "1": "itop-config", + "name": "itop-config", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "300", + "id": "300", + "1": "itop-files-information", + "name": "itop-files-information", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "301", + "id": "301", + "1": "itop-portal-base", + "name": "itop-portal-base", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "302", + "id": "302", + "1": "itop-profiles-itil", + "name": "itop-profiles-itil", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "303", + "id": "303", + "1": "itop-sla-computation", + "name": "itop-sla-computation", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "304", + "id": "304", + "1": "itop-structure", + "name": "itop-structure", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "305", + "id": "305", + "1": "itop-welcome-itil", + "name": "itop-welcome-itil", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "306", + "id": "306", + "1": "itop-config-mgmt", + "name": "itop-config-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "307", + "id": "307", + "1": "itop-attachments", + "name": "itop-attachments", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nOptional\nVisible (during the setup)", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "308", + "id": "308", + "1": "itop-tickets", + "name": "itop-tickets", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "309", + "id": "309", + "1": "combodo-db-tools", + "name": "combodo-db-tools", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.0.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.0.0", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "310", + "id": "310", + "1": "itop-core-update", + "name": "itop-core-update", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-files-information\/2.7.0\nDepends on module: combodo-db-tools\/2.7.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-files-information\/2.7.0\nDepends on module: combodo-db-tools\/2.7.0", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "311", + "id": "311", + "1": "itop-hub-connector", + "name": "itop-hub-connector", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "312", + "id": "312", + "1": "itop-oauth-client", + "name": "itop-oauth-client", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-welcome-itil\/3.1.0,", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-welcome-itil\/3.1.0,", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "313", + "id": "313", + "1": "itop-themes-compat", + "name": "itop-themes-compat", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.1.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.1.0", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "314", + "id": "314", + "1": "itop-datacenter-mgmt", + "name": "itop-datacenter-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "315", + "id": "315", + "1": "itop-endusers-devices", + "name": "itop-endusers-devices", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "316", + "id": "316", + "1": "itop-storage-mgmt", + "name": "itop-storage-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "317", + "id": "317", + "1": "itop-virtualization-mgmt", + "name": "itop-virtualization-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "318", + "id": "318", + "1": "itop-bridge-cmdb-ticket", + "name": "itop-bridge-cmdb-ticket", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-tickets\/2.7.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-tickets\/2.7.0", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "319", + "id": "319", + "1": "itop-bridge-virtualization-storage", + "name": "itop-bridge-virtualization-storage", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-storage-mgmt\/2.2.0\nDepends on module: itop-virtualization-mgmt\/2.2.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-storage-mgmt\/2.2.0\nDepends on module: itop-virtualization-mgmt\/2.2.0", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "320", + "id": "320", + "1": "itop-service-mgmt", + "name": "itop-service-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.0.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.0.0", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "321", + "id": "321", + "1": "itop-bridge-cmdb-services", + "name": "itop-bridge-cmdb-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "322", + "id": "322", + "1": "itop-bridge-datacenter-mgmt-services", + "name": "itop-bridge-datacenter-mgmt-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-datacenter-mgmt\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-datacenter-mgmt\/3.1.0", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "323", + "id": "323", + "1": "itop-bridge-endusers-devices-services", + "name": "itop-bridge-endusers-devices-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-endusers-devices\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-endusers-devices\/3.1.0", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "324", + "id": "324", + "1": "itop-bridge-storage-mgmt-services", + "name": "itop-bridge-storage-mgmt-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-storage-mgmt\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-storage-mgmt\/3.1.0", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "325", + "id": "325", + "1": "itop-bridge-virtualization-mgmt-services", + "name": "itop-bridge-virtualization-mgmt-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-virtualization-mgmt\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-virtualization-mgmt\/3.1.0", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "326", + "id": "326", + "1": "itop-request-mgmt", + "name": "itop-request-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.4.0", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "327", + "id": "327", + "1": "itop-portal", + "name": "itop-portal", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-portal-base\/2.7.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-portal-base\/2.7.0", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "328", + "id": "328", + "1": "itop-change-mgmt", + "name": "itop-change-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:47:54", + "installed": "2025-11-10 11:47:54", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0\nDepends on module: itop-tickets\/2.0.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0\nDepends on module: itop-tickets\/2.0.0", + "5": "289", + "parent_id": "289", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "329", + "id": "329", + "1": "datamodel", + "name": "datamodel", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "{\"source_dir\":\"datamodels\\\/2.x\\\/\"}", + "comment": "{\"source_dir\":\"datamodels\\\/2.x\\\/\"}", + "5": "0", + "parent_id": "0", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "330", + "id": "330", + "1": "iTop", + "name": "iTop", + "2": "3.3.0-dev-svn", + "version": "3.3.0-dev-svn", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nBuilt on $WCNOW$", + "comment": "Done by the setup program\nBuilt on $WCNOW$", + "5": "0", + "parent_id": "0", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "331", + "id": "331", + "1": "authent-cas", + "name": "authent-cas", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nMandatory\nVisible (during the setup)", + "comment": "Done by the setup program\nMandatory\nVisible (during the setup)", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "332", + "id": "332", + "1": "authent-external", + "name": "authent-external", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nVisible (during the setup)", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "333", + "id": "333", + "1": "authent-ldap", + "name": "authent-ldap", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nVisible (during the setup)", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "334", + "id": "334", + "1": "authent-local", + "name": "authent-local", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nMandatory\nVisible (during the setup)", + "comment": "Done by the setup program\nMandatory\nVisible (during the setup)", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "335", + "id": "335", + "1": "combodo-backoffice-darkmoon-theme", + "name": "combodo-backoffice-darkmoon-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "336", + "id": "336", + "1": "combodo-backoffice-fullmoon-high-contrast-theme", + "name": "combodo-backoffice-fullmoon-high-contrast-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "337", + "id": "337", + "1": "combodo-backoffice-fullmoon-protanopia-deuteranopia-theme", + "name": "combodo-backoffice-fullmoon-protanopia-deuteranopia-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "338", + "id": "338", + "1": "combodo-backoffice-fullmoon-tritanopia-theme", + "name": "combodo-backoffice-fullmoon-tritanopia-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "339", + "id": "339", + "1": "itop-backup", + "name": "itop-backup", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "340", + "id": "340", + "1": "itop-config", + "name": "itop-config", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "341", + "id": "341", + "1": "itop-files-information", + "name": "itop-files-information", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "342", + "id": "342", + "1": "itop-portal-base", + "name": "itop-portal-base", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "343", + "id": "343", + "1": "itop-profiles-itil", + "name": "itop-profiles-itil", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "344", + "id": "344", + "1": "itop-sla-computation", + "name": "itop-sla-computation", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "345", + "id": "345", + "1": "itop-structure", + "name": "itop-structure", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "346", + "id": "346", + "1": "itop-welcome-itil", + "name": "itop-welcome-itil", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "347", + "id": "347", + "1": "itop-config-mgmt", + "name": "itop-config-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "348", + "id": "348", + "1": "itop-attachments", + "name": "itop-attachments", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nVisible (during the setup)", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "349", + "id": "349", + "1": "itop-tickets", + "name": "itop-tickets", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "350", + "id": "350", + "1": "combodo-db-tools", + "name": "combodo-db-tools", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.0.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.0.0", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "351", + "id": "351", + "1": "itop-core-update", + "name": "itop-core-update", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-files-information\/2.7.0\nDepends on module: combodo-db-tools\/2.7.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-files-information\/2.7.0\nDepends on module: combodo-db-tools\/2.7.0", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "352", + "id": "352", + "1": "itop-hub-connector", + "name": "itop-hub-connector", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "353", + "id": "353", + "1": "itop-oauth-client", + "name": "itop-oauth-client", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-welcome-itil\/3.1.0,", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-welcome-itil\/3.1.0,", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "354", + "id": "354", + "1": "itop-themes-compat", + "name": "itop-themes-compat", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.1.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.1.0", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "355", + "id": "355", + "1": "itop-datacenter-mgmt", + "name": "itop-datacenter-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "356", + "id": "356", + "1": "itop-endusers-devices", + "name": "itop-endusers-devices", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "357", + "id": "357", + "1": "itop-storage-mgmt", + "name": "itop-storage-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "358", + "id": "358", + "1": "itop-virtualization-mgmt", + "name": "itop-virtualization-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "359", + "id": "359", + "1": "itop-bridge-cmdb-ticket", + "name": "itop-bridge-cmdb-ticket", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-tickets\/2.7.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-tickets\/2.7.0", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "360", + "id": "360", + "1": "itop-bridge-virtualization-storage", + "name": "itop-bridge-virtualization-storage", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-storage-mgmt\/2.2.0\nDepends on module: itop-virtualization-mgmt\/2.2.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-storage-mgmt\/2.2.0\nDepends on module: itop-virtualization-mgmt\/2.2.0", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "361", + "id": "361", + "1": "itop-service-mgmt", + "name": "itop-service-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.0.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.0.0", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "362", + "id": "362", + "1": "itop-bridge-cmdb-services", + "name": "itop-bridge-cmdb-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "363", + "id": "363", + "1": "itop-bridge-datacenter-mgmt-services", + "name": "itop-bridge-datacenter-mgmt-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-datacenter-mgmt\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-datacenter-mgmt\/3.1.0", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "364", + "id": "364", + "1": "itop-bridge-endusers-devices-services", + "name": "itop-bridge-endusers-devices-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-endusers-devices\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-endusers-devices\/3.1.0", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "365", + "id": "365", + "1": "itop-bridge-storage-mgmt-services", + "name": "itop-bridge-storage-mgmt-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-storage-mgmt\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-storage-mgmt\/3.1.0", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "366", + "id": "366", + "1": "itop-bridge-virtualization-mgmt-services", + "name": "itop-bridge-virtualization-mgmt-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-virtualization-mgmt\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-virtualization-mgmt\/3.1.0", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "367", + "id": "367", + "1": "itop-request-mgmt", + "name": "itop-request-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.4.0", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "368", + "id": "368", + "1": "itop-portal", + "name": "itop-portal", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-portal-base\/2.7.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-portal-base\/2.7.0", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "369", + "id": "369", + "1": "itop-change-mgmt", + "name": "itop-change-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0\nDepends on module: itop-tickets\/2.0.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0\nDepends on module: itop-tickets\/2.0.0", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "370", + "id": "370", + "1": "datamodel", + "name": "datamodel", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "{\"source_dir\":\"datamodels\\\/2.x\\\/\"}", + "comment": "{\"source_dir\":\"datamodels\\\/2.x\\\/\"}", + "5": "0", + "parent_id": "0", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "371", + "id": "371", + "1": "iTop", + "name": "iTop", + "2": "3.3.0-dev-svn", + "version": "3.3.0-dev-svn", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nBuilt on $WCNOW$", + "comment": "Done by the setup program\nBuilt on $WCNOW$", + "5": "0", + "parent_id": "0", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "372", + "id": "372", + "1": "authent-cas", + "name": "authent-cas", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nMandatory\nVisible (during the setup)", + "comment": "Done by the setup program\nMandatory\nVisible (during the setup)", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "373", + "id": "373", + "1": "authent-external", + "name": "authent-external", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nOptional\nVisible (during the setup)", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "374", + "id": "374", + "1": "authent-ldap", + "name": "authent-ldap", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nOptional\nVisible (during the setup)", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "375", + "id": "375", + "1": "authent-local", + "name": "authent-local", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nMandatory\nVisible (during the setup)", + "comment": "Done by the setup program\nMandatory\nVisible (during the setup)", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "376", + "id": "376", + "1": "combodo-backoffice-darkmoon-theme", + "name": "combodo-backoffice-darkmoon-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "377", + "id": "377", + "1": "combodo-backoffice-fullmoon-high-contrast-theme", + "name": "combodo-backoffice-fullmoon-high-contrast-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "378", + "id": "378", + "1": "combodo-backoffice-fullmoon-protanopia-deuteranopia-theme", + "name": "combodo-backoffice-fullmoon-protanopia-deuteranopia-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "379", + "id": "379", + "1": "combodo-backoffice-fullmoon-tritanopia-theme", + "name": "combodo-backoffice-fullmoon-tritanopia-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "380", + "id": "380", + "1": "itop-backup", + "name": "itop-backup", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "381", + "id": "381", + "1": "itop-config", + "name": "itop-config", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "382", + "id": "382", + "1": "itop-files-information", + "name": "itop-files-information", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "383", + "id": "383", + "1": "itop-portal-base", + "name": "itop-portal-base", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "384", + "id": "384", + "1": "itop-profiles-itil", + "name": "itop-profiles-itil", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "385", + "id": "385", + "1": "itop-sla-computation", + "name": "itop-sla-computation", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "386", + "id": "386", + "1": "itop-structure", + "name": "itop-structure", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "387", + "id": "387", + "1": "itop-welcome-itil", + "name": "itop-welcome-itil", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "388", + "id": "388", + "1": "itop-config-mgmt", + "name": "itop-config-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "389", + "id": "389", + "1": "itop-attachments", + "name": "itop-attachments", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nOptional\nVisible (during the setup)", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "390", + "id": "390", + "1": "itop-tickets", + "name": "itop-tickets", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "391", + "id": "391", + "1": "combodo-db-tools", + "name": "combodo-db-tools", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.0.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.0.0", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "392", + "id": "392", + "1": "itop-core-update", + "name": "itop-core-update", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-files-information\/2.7.0\nDepends on module: combodo-db-tools\/2.7.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-files-information\/2.7.0\nDepends on module: combodo-db-tools\/2.7.0", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "393", + "id": "393", + "1": "itop-hub-connector", + "name": "itop-hub-connector", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "394", + "id": "394", + "1": "itop-oauth-client", + "name": "itop-oauth-client", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-welcome-itil\/3.1.0,", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-welcome-itil\/3.1.0,", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "395", + "id": "395", + "1": "itop-themes-compat", + "name": "itop-themes-compat", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.1.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.1.0", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "396", + "id": "396", + "1": "itop-datacenter-mgmt", + "name": "itop-datacenter-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "397", + "id": "397", + "1": "itop-endusers-devices", + "name": "itop-endusers-devices", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "398", + "id": "398", + "1": "itop-storage-mgmt", + "name": "itop-storage-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "399", + "id": "399", + "1": "itop-virtualization-mgmt", + "name": "itop-virtualization-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "400", + "id": "400", + "1": "itop-bridge-cmdb-ticket", + "name": "itop-bridge-cmdb-ticket", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-tickets\/2.7.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-tickets\/2.7.0", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "401", + "id": "401", + "1": "itop-bridge-virtualization-storage", + "name": "itop-bridge-virtualization-storage", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-storage-mgmt\/2.2.0\nDepends on module: itop-virtualization-mgmt\/2.2.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-storage-mgmt\/2.2.0\nDepends on module: itop-virtualization-mgmt\/2.2.0", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "402", + "id": "402", + "1": "itop-service-mgmt", + "name": "itop-service-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.0.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.0.0", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "403", + "id": "403", + "1": "itop-bridge-cmdb-services", + "name": "itop-bridge-cmdb-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "404", + "id": "404", + "1": "itop-bridge-datacenter-mgmt-services", + "name": "itop-bridge-datacenter-mgmt-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-datacenter-mgmt\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-datacenter-mgmt\/3.1.0", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "405", + "id": "405", + "1": "itop-bridge-endusers-devices-services", + "name": "itop-bridge-endusers-devices-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-endusers-devices\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-endusers-devices\/3.1.0", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "406", + "id": "406", + "1": "itop-bridge-storage-mgmt-services", + "name": "itop-bridge-storage-mgmt-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-storage-mgmt\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-storage-mgmt\/3.1.0", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "407", + "id": "407", + "1": "itop-bridge-virtualization-mgmt-services", + "name": "itop-bridge-virtualization-mgmt-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-virtualization-mgmt\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-virtualization-mgmt\/3.1.0", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "408", + "id": "408", + "1": "itop-request-mgmt", + "name": "itop-request-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.4.0", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "409", + "id": "409", + "1": "itop-portal", + "name": "itop-portal", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-portal-base\/2.7.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-portal-base\/2.7.0", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "410", + "id": "410", + "1": "itop-change-mgmt", + "name": "itop-change-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 15:32:24", + "installed": "2025-11-10 15:32:24", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0\nDepends on module: itop-tickets\/2.0.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0\nDepends on module: itop-tickets\/2.0.0", + "5": "371", + "parent_id": "371", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "411", + "id": "411", + "1": "datamodel", + "name": "datamodel", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "{\"source_dir\":\"datamodels\\\/2.x\\\/\"}", + "comment": "{\"source_dir\":\"datamodels\\\/2.x\\\/\"}", + "5": "0", + "parent_id": "0", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "412", + "id": "412", + "1": "iTop", + "name": "iTop", + "2": "3.3.0-dev-svn", + "version": "3.3.0-dev-svn", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nBuilt on $WCNOW$", + "comment": "Done by the setup program\nBuilt on $WCNOW$", + "5": "0", + "parent_id": "0", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "413", + "id": "413", + "1": "authent-cas", + "name": "authent-cas", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nMandatory\nVisible (during the setup)", + "comment": "Done by the setup program\nMandatory\nVisible (during the setup)", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "414", + "id": "414", + "1": "authent-external", + "name": "authent-external", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nOptional\nVisible (during the setup)", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "415", + "id": "415", + "1": "authent-ldap", + "name": "authent-ldap", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nOptional\nVisible (during the setup)", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "416", + "id": "416", + "1": "authent-local", + "name": "authent-local", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nMandatory\nVisible (during the setup)", + "comment": "Done by the setup program\nMandatory\nVisible (during the setup)", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "417", + "id": "417", + "1": "combodo-backoffice-darkmoon-theme", + "name": "combodo-backoffice-darkmoon-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "418", + "id": "418", + "1": "combodo-backoffice-fullmoon-high-contrast-theme", + "name": "combodo-backoffice-fullmoon-high-contrast-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "419", + "id": "419", + "1": "combodo-backoffice-fullmoon-protanopia-deuteranopia-theme", + "name": "combodo-backoffice-fullmoon-protanopia-deuteranopia-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "420", + "id": "420", + "1": "combodo-backoffice-fullmoon-tritanopia-theme", + "name": "combodo-backoffice-fullmoon-tritanopia-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "421", + "id": "421", + "1": "itop-backup", + "name": "itop-backup", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "422", + "id": "422", + "1": "itop-config", + "name": "itop-config", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "423", + "id": "423", + "1": "itop-files-information", + "name": "itop-files-information", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "424", + "id": "424", + "1": "itop-portal-base", + "name": "itop-portal-base", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "425", + "id": "425", + "1": "itop-profiles-itil", + "name": "itop-profiles-itil", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "426", + "id": "426", + "1": "itop-sla-computation", + "name": "itop-sla-computation", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "427", + "id": "427", + "1": "itop-structure", + "name": "itop-structure", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "428", + "id": "428", + "1": "itop-welcome-itil", + "name": "itop-welcome-itil", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "429", + "id": "429", + "1": "itop-config-mgmt", + "name": "itop-config-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "430", + "id": "430", + "1": "itop-attachments", + "name": "itop-attachments", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nOptional\nVisible (during the setup)", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "431", + "id": "431", + "1": "itop-tickets", + "name": "itop-tickets", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "432", + "id": "432", + "1": "combodo-db-tools", + "name": "combodo-db-tools", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.0.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.0.0", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "433", + "id": "433", + "1": "itop-core-update", + "name": "itop-core-update", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-files-information\/2.7.0\nDepends on module: combodo-db-tools\/2.7.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-files-information\/2.7.0\nDepends on module: combodo-db-tools\/2.7.0", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "434", + "id": "434", + "1": "itop-hub-connector", + "name": "itop-hub-connector", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "435", + "id": "435", + "1": "itop-oauth-client", + "name": "itop-oauth-client", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-welcome-itil\/3.1.0,", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-welcome-itil\/3.1.0,", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "436", + "id": "436", + "1": "itop-themes-compat", + "name": "itop-themes-compat", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.1.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.1.0", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "437", + "id": "437", + "1": "itop-datacenter-mgmt", + "name": "itop-datacenter-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "438", + "id": "438", + "1": "itop-endusers-devices", + "name": "itop-endusers-devices", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "439", + "id": "439", + "1": "itop-storage-mgmt", + "name": "itop-storage-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "440", + "id": "440", + "1": "itop-virtualization-mgmt", + "name": "itop-virtualization-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "441", + "id": "441", + "1": "itop-bridge-cmdb-ticket", + "name": "itop-bridge-cmdb-ticket", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-tickets\/2.7.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-tickets\/2.7.0", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "442", + "id": "442", + "1": "itop-bridge-virtualization-storage", + "name": "itop-bridge-virtualization-storage", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-storage-mgmt\/2.2.0\nDepends on module: itop-virtualization-mgmt\/2.2.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-storage-mgmt\/2.2.0\nDepends on module: itop-virtualization-mgmt\/2.2.0", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "443", + "id": "443", + "1": "itop-service-mgmt", + "name": "itop-service-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.0.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.0.0", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "444", + "id": "444", + "1": "itop-bridge-cmdb-services", + "name": "itop-bridge-cmdb-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "445", + "id": "445", + "1": "itop-bridge-datacenter-mgmt-services", + "name": "itop-bridge-datacenter-mgmt-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-datacenter-mgmt\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-datacenter-mgmt\/3.1.0", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "446", + "id": "446", + "1": "itop-bridge-endusers-devices-services", + "name": "itop-bridge-endusers-devices-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-endusers-devices\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-endusers-devices\/3.1.0", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "447", + "id": "447", + "1": "itop-bridge-storage-mgmt-services", + "name": "itop-bridge-storage-mgmt-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-storage-mgmt\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-storage-mgmt\/3.1.0", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "448", + "id": "448", + "1": "itop-bridge-virtualization-mgmt-services", + "name": "itop-bridge-virtualization-mgmt-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-virtualization-mgmt\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-virtualization-mgmt\/3.1.0", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "449", + "id": "449", + "1": "itop-request-mgmt", + "name": "itop-request-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.4.0", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "450", + "id": "450", + "1": "itop-portal", + "name": "itop-portal", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-portal-base\/2.7.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-portal-base\/2.7.0", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "451", + "id": "451", + "1": "itop-change-mgmt", + "name": "itop-change-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 16:14:15", + "installed": "2025-11-10 16:14:15", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0\nDepends on module: itop-tickets\/2.0.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0\nDepends on module: itop-tickets\/2.0.0", + "5": "412", + "parent_id": "412", + "6": "yes", + "uninstallable": "yes" + } +] \ No newline at end of file diff --git a/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/priv_modules2.json b/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/priv_modules2.json new file mode 100644 index 0000000000..8f4244366f --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/priv_modules2.json @@ -0,0 +1,642 @@ +[ + { + "0": "330", + "id": "330", + "1": "iTop", + "name": "iTop", + "2": "3.3.0-dev-svn", + "version": "3.3.0-dev-svn", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nBuilt on $WCNOW$", + "comment": "Done by the setup program\nBuilt on $WCNOW$", + "5": "0", + "parent_id": "0", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "331", + "id": "331", + "1": "authent-cas", + "name": "authent-cas", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nMandatory\nVisible (during the setup)", + "comment": "Done by the setup program\nMandatory\nVisible (during the setup)", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "332", + "id": "332", + "1": "authent-external", + "name": "authent-external", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nVisible (during the setup)", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "333", + "id": "333", + "1": "authent-ldap", + "name": "authent-ldap", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nVisible (during the setup)", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "334", + "id": "334", + "1": "authent-local", + "name": "authent-local", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nMandatory\nVisible (during the setup)", + "comment": "Done by the setup program\nMandatory\nVisible (during the setup)", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "335", + "id": "335", + "1": "combodo-backoffice-darkmoon-theme", + "name": "combodo-backoffice-darkmoon-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "336", + "id": "336", + "1": "combodo-backoffice-fullmoon-high-contrast-theme", + "name": "combodo-backoffice-fullmoon-high-contrast-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "337", + "id": "337", + "1": "combodo-backoffice-fullmoon-protanopia-deuteranopia-theme", + "name": "combodo-backoffice-fullmoon-protanopia-deuteranopia-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "338", + "id": "338", + "1": "combodo-backoffice-fullmoon-tritanopia-theme", + "name": "combodo-backoffice-fullmoon-tritanopia-theme", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "339", + "id": "339", + "1": "itop-backup", + "name": "itop-backup", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "340", + "id": "340", + "1": "itop-config", + "name": "itop-config", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "341", + "id": "341", + "1": "itop-files-information", + "name": "itop-files-information", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "342", + "id": "342", + "1": "itop-portal-base", + "name": "itop-portal-base", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "343", + "id": "343", + "1": "itop-profiles-itil", + "name": "itop-profiles-itil", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "344", + "id": "344", + "1": "itop-sla-computation", + "name": "itop-sla-computation", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "345", + "id": "345", + "1": "itop-structure", + "name": "itop-structure", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "346", + "id": "346", + "1": "itop-welcome-itil", + "name": "itop-welcome-itil", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "comment": "Done by the setup program\nMandatory\nHidden (selected automatically)", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "347", + "id": "347", + "1": "itop-config-mgmt", + "name": "itop-config-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "348", + "id": "348", + "1": "itop-attachments", + "name": "itop-attachments", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nVisible (during the setup)", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "349", + "id": "349", + "1": "itop-tickets", + "name": "itop-tickets", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/2.7.1", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "350", + "id": "350", + "1": "combodo-db-tools", + "name": "combodo-db-tools", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.0.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.0.0", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "351", + "id": "351", + "1": "itop-core-update", + "name": "itop-core-update", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-files-information\/2.7.0\nDepends on module: combodo-db-tools\/2.7.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-files-information\/2.7.0\nDepends on module: combodo-db-tools\/2.7.0", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "352", + "id": "352", + "1": "itop-hub-connector", + "name": "itop-hub-connector", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "353", + "id": "353", + "1": "itop-oauth-client", + "name": "itop-oauth-client", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-welcome-itil\/3.1.0,", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-welcome-itil\/3.1.0,", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "354", + "id": "354", + "1": "itop-themes-compat", + "name": "itop-themes-compat", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.1.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-structure\/3.1.0", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "355", + "id": "355", + "1": "itop-datacenter-mgmt", + "name": "itop-datacenter-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "356", + "id": "356", + "1": "itop-endusers-devices", + "name": "itop-endusers-devices", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "357", + "id": "357", + "1": "itop-storage-mgmt", + "name": "itop-storage-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "358", + "id": "358", + "1": "itop-virtualization-mgmt", + "name": "itop-virtualization-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.4.0", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "359", + "id": "359", + "1": "itop-bridge-cmdb-ticket", + "name": "itop-bridge-cmdb-ticket", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-tickets\/2.7.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-tickets\/2.7.0", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "360", + "id": "360", + "1": "itop-bridge-virtualization-storage", + "name": "itop-bridge-virtualization-storage", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-storage-mgmt\/2.2.0\nDepends on module: itop-virtualization-mgmt\/2.2.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-storage-mgmt\/2.2.0\nDepends on module: itop-virtualization-mgmt\/2.2.0", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "361", + "id": "361", + "1": "itop-service-mgmt", + "name": "itop-service-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.0.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.0.0", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "362", + "id": "362", + "1": "itop-bridge-cmdb-services", + "name": "itop-bridge-cmdb-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "363", + "id": "363", + "1": "itop-bridge-datacenter-mgmt-services", + "name": "itop-bridge-datacenter-mgmt-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-datacenter-mgmt\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-datacenter-mgmt\/3.1.0", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "364", + "id": "364", + "1": "itop-bridge-endusers-devices-services", + "name": "itop-bridge-endusers-devices-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-endusers-devices\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-endusers-devices\/3.1.0", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "365", + "id": "365", + "1": "itop-bridge-storage-mgmt-services", + "name": "itop-bridge-storage-mgmt-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-storage-mgmt\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-storage-mgmt\/3.1.0", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "366", + "id": "366", + "1": "itop-bridge-virtualization-mgmt-services", + "name": "itop-bridge-virtualization-mgmt-services", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-virtualization-mgmt\/3.1.0", + "comment": "Done by the setup program\nOptional\nHidden (selected automatically)\nDepends on module: itop-config-mgmt\/2.7.1\nDepends on module: itop-service-mgmt\/2.7.1 || itop-service-mgmt-provider\/2.7.1\nDepends on module: itop-virtualization-mgmt\/3.1.0", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "367", + "id": "367", + "1": "itop-request-mgmt", + "name": "itop-request-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.4.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-tickets\/2.4.0", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "368", + "id": "368", + "1": "itop-portal", + "name": "itop-portal", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-portal-base\/2.7.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-portal-base\/2.7.0", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "369", + "id": "369", + "1": "itop-change-mgmt", + "name": "itop-change-mgmt", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0\nDepends on module: itop-tickets\/2.0.0", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)\nDepends on module: itop-config-mgmt\/2.2.0\nDepends on module: itop-tickets\/2.0.0", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + } +] \ No newline at end of file diff --git a/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/priv_modules_simpleusecase.json b/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/priv_modules_simpleusecase.json new file mode 100644 index 0000000000..2576b7f9ea --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/moduleinstallation/ressources/priv_modules_simpleusecase.json @@ -0,0 +1,50 @@ +[ + { + "0": "330", + "id": "330", + "1": "iTop", + "name": "iTop", + "2": "3.3.0-dev-svn", + "version": "3.3.0-dev-svn", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nBuilt on $WCNOW$", + "comment": "Done by the setup program\nBuilt on $WCNOW$", + "5": "0", + "parent_id": "0", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "331", + "id": "331", + "1": "mandatory_module", + "name": "mandatory_module", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nMandatory\nVisible (during the setup)", + "comment": "Done by the setup program\nMandatory\nVisible (during the setup)", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "yes" + }, + { + "0": "332", + "id": "332", + "1": "optional_module", + "name": "optional_module", + "2": "3.3.0", + "version": "3.3.0", + "3": "2025-11-10 11:50:12", + "installed": "2025-11-10 11:50:12", + "4": "Done by the setup program\nOptional\nVisible (during the setup)", + "comment": "Done by the setup program\nOptional\nVisible (during the setup)", + "5": "330", + "parent_id": "330", + "6": "yes", + "uninstallable": "no" + } +] \ No newline at end of file diff --git a/tests/php-unit-tests/unitary-tests/setup/ressources/all_extensions_from_datamodels.json b/tests/php-unit-tests/unitary-tests/setup/ressources/all_extensions_from_datamodels.json new file mode 100644 index 0000000000..68531962d5 --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/ressources/all_extensions_from_datamodels.json @@ -0,0 +1,316 @@ +[ + { + "sCode": "itop-config-mgmt-core", + "sSource": "datamodels", + "sVersion": "ITOP_VERSION", + "aModules": [ + "itop-structure", + "itop-config-mgmt", + "itop-attachments", + "itop-profiles-itil", + "itop-welcome-itil", + "itop-tickets", + "itop-files-information", + "combodo-db-tools", + "itop-core-update", + "itop-hub-connector", + "itop-oauth-client", + "combodo-backoffice-darkmoon-theme", + "combodo-backoffice-fullmoon-high-contrast-theme", + "combodo-backoffice-fullmoon-protanopia-deuteranopia-theme", + "combodo-backoffice-fullmoon-tritanopia-theme", + "itop-themes-compat", + "combodo-my-account", + "combodo-my-account-user-info", + "combodo-oauth2-client", + "itop-attribute-class-set", + "itop-attribute-encrypted-password", + "itop-ui-copypaste" + ], + "aModuleVersion": { + "itop-structure": "3.3.0", + "itop-config-mgmt": "3.3.0" + }, + "aModuleInfo": { + "itop-structure": { + "label": "Core iTop Structure", + "category": "business", + "dependencies": [], + "mandatory": true, + "visible": false, + "installer": "StructureInstaller", + "datamodel": [ + "main.itop-structure.php" + ], + "data.struct": [], + "data.sample": [ + "data\/data.sample.organizations.xml", + "data\/data.sample.locations.xml", + "data\/data.sample.persons.xml", + "data\/data.sample.teams.xml", + "data\/data.sample.contactteam.xml", + "data\/data.sample.contacttype.xml" + ], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "APPROOTtests\/php-unit-tests\/unitary-tests\/setup\/ressources\/datamodels\/2.x\/itop-structure\/module.itop-structure.php" + }, + "itop-config-mgmt": { + "label": "Configuration Management (CMDB)", + "category": "business", + "dependencies": [ + "itop-structure\/2.7.1" + ], + "mandatory": false, + "visible": true, + "installer": "ConfigMgmtInstaller", + "datamodel": [ + "model.itop-config-mgmt.php", + "main.itop-config-mgmt.php" + ], + "data.struct": [ + "data\/en_us.data.itop-brand.xml", + "data\/en_us.data.itop-networkdevicetype.xml", + "data\/en_us.data.itop-osfamily.xml", + "data\/en_us.data.itop-osversion.xml" + ], + "data.sample": [ + "data\/data.sample.model.xml", + "data\/data.sample.networkdevicetype.xml", + "data\/data.sample.servers.xml", + "data\/data.sample.nw-devices.xml", + "data\/data.sample.software.xml", + "data\/data.sample.dbserver.xml", + "data\/data.sample.dbschema.xml", + "data\/data.sample.webserver.xml", + "data\/data.sample.webapp.xml", + "data\/data.sample.applications.xml", + "data\/data.sample.applicationsolutionci.xml" + ], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "APPROOT\/tests\/php-unit-tests\/unitary-tests\/setup\/ressources\/datamodels\/2.x\/itop-config-mgmt\/module.itop-config-mgmt.php" + } + } + }, + { + "sCode": "itop-config-mgmt-datacenter", + "sSource": "datamodels", + "sVersion": "ITOP_VERSION", + "aModules": [ + "itop-datacenter-mgmt" + ], + "aModuleVersion": [], + "aModuleInfo": [] + }, + { + "sCode": "itop-config-mgmt-end-user", + "sSource": "datamodels", + "sVersion": "ITOP_VERSION", + "aModules": [ + "itop-endusers-devices" + ], + "aModuleVersion": [], + "aModuleInfo": [] + }, + { + "sCode": "itop-config-mgmt-storage", + "sSource": "datamodels", + "sVersion": "ITOP_VERSION", + "aModules": [ + "itop-storage-mgmt" + ], + "aModuleVersion": [], + "aModuleInfo": [] + }, + { + "sCode": "itop-container-mgmt", + "sSource": "datamodels", + "sVersion": "ITOP_VERSION", + "aModules": [ + "itop-container-mgmt" + ], + "aModuleVersion": [], + "aModuleInfo": [] + }, + { + "sCode": "itop-config-mgmt-virtualization", + "sSource": "datamodels", + "sVersion": "ITOP_VERSION", + "aModules": [ + "itop-virtualization-mgmt" + ], + "aModuleVersion": [], + "aModuleInfo": [] + }, + { + "sCode": "itop-service-mgmt-enterprise", + "sSource": "datamodels", + "sVersion": "ITOP_VERSION", + "aModules": [ + "itop-service-mgmt" + ], + "aModuleVersion": { + "itop-service-mgmt": "3.3.0" + }, + "aModuleInfo": { + "itop-service-mgmt": { + "label": "Service Management", + "category": "business", + "dependencies": [ + "itop-tickets\/2.0.0" + ], + "mandatory": false, + "visible": true, + "installer": "ServiceMgmtInstaller", + "datamodel": [], + "data.struct": [], + "data.sample": [ + "data\/data.sample.organizations.xml", + "data\/data.sample.contracts.xml", + "data\/data.sample.servicefamilies.xml", + "data\/data.sample.services.xml", + "data\/data.sample.serviceelements.xml", + "data\/data.sample.sla.xml", + "data\/data.sample.slt.xml", + "data\/data.sample.sltsla.xml", + "data\/data.sample.contractservice.xml", + "data\/data.sample.deliverymodelcontact.xml" + ], + "doc.manual_setup": "", + "doc.more_information": "", + "settings": [], + "module_file_path": "APPROOT\/tests\/php-unit-tests\/unitary-tests\/setup\/ressources\/datamodels\/2.x\/itop-service-mgmt\/module.itop-service-mgmt.php" + } + } + }, + { + "sCode": "itop-service-mgmt-service-provider", + "sSource": "datamodels", + "sVersion": "ITOP_VERSION", + "aModules": [ + "itop-service-mgmt-provider" + ], + "aModuleVersion": [], + "aModuleInfo": [] + }, + { + "sCode": "itop-ticket-mgmt-simple-ticket-enhanced-portal", + "sSource": "datamodels", + "sVersion": "ITOP_VERSION", + "aModules": [ + "itop-portal", + "itop-portal-base" + ], + "aModuleVersion": [], + "aModuleInfo": [] + }, + { + "sCode": "itop-ticket-mgmt-simple-ticket", + "sSource": "datamodels", + "sVersion": "ITOP_VERSION", + "aModules": [ + "itop-request-mgmt" + ], + "aModuleVersion": [], + "aModuleInfo": [] + }, + { + "sCode": "itop-ticket-mgmt-itil-user-request", + "sSource": "datamodels", + "sVersion": "ITOP_VERSION", + "aModules": [ + "itop-request-mgmt-itil" + ], + "aModuleVersion": [], + "aModuleInfo": [] + }, + { + "sCode": "itop-ticket-mgmt-itil-incident", + "sSource": "datamodels", + "sVersion": "ITOP_VERSION", + "aModules": [ + "itop-incident-mgmt-itil" + ], + "aModuleVersion": [], + "aModuleInfo": [] + }, + { + "sCode": "itop-ticket-mgmt-itil-enhanced-portal", + "sSource": "datamodels", + "sVersion": "ITOP_VERSION", + "aModules": [ + "itop-portal", + "itop-portal-base" + ], + "aModuleVersion": [], + "aModuleInfo": [] + }, + { + "sCode": "itop-ticket-mgmt-itil", + "sSource": "datamodels", + "sVersion": "ITOP_VERSION", + "aModules": [], + "aModuleVersion": [], + "aModuleInfo": [] + }, + { + "sCode": "itop-ticket-mgmt-none", + "sSource": "datamodels", + "sVersion": "ITOP_VERSION", + "aModules": [], + "aModuleVersion": [], + "aModuleInfo": [] + }, + { + "sCode": "itop-change-mgmt-simple", + "sSource": "datamodels", + "sVersion": "ITOP_VERSION", + "aModules": [ + "itop-change-mgmt" + ], + "aModuleVersion": [], + "aModuleInfo": [] + }, + { + "sCode": "itop-change-mgmt-itil", + "sSource": "datamodels", + "sVersion": "ITOP_VERSION", + "aModules": [ + "itop-change-mgmt-itil" + ], + "aModuleVersion": [], + "aModuleInfo": [] + }, + { + "sCode": "itop-change-mgmt-none", + "sSource": "datamodels", + "sVersion": "ITOP_VERSION", + "aModules": [], + "aModuleVersion": [], + "aModuleInfo": [] + }, + { + "sCode": "itop-kown-error-mgmt", + "sSource": "datamodels", + "sVersion": "ITOP_VERSION", + "aModules": [ + "itop-faq-light", + "itop-knownerror-mgmt" + ], + "aModuleVersion": [], + "aModuleInfo": [] + }, + { + "sCode": "itop-problem-mgmt", + "sSource": "datamodels", + "sVersion": "ITOP_VERSION", + "aModules": [ + "itop-problem-mgmt" + ], + "aModuleVersion": [], + "aModuleInfo": [] + } +] \ No newline at end of file diff --git a/tests/php-unit-tests/unitary-tests/setup/ressources/datamodels/2.x/installation.xml b/tests/php-unit-tests/unitary-tests/setup/ressources/datamodels/2.x/installation.xml new file mode 100644 index 0000000000..70d3866c17 --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/ressources/datamodels/2.x/installation.xml @@ -0,0 +1,243 @@ + + + + + Configuration Management options + The options below allow you to configure the type of elements that are to be managed inside iTop.]]> + /images/icons/icons8-apps-tab.svg + + + itop-config-mgmt-core + Configuration Management Core + All the base objects that are mandatory in the iTop CMDB: Organizations, Locations, Teams, Persons, etc. + + itop-structure + itop-config-mgmt + itop-attachments + itop-profiles-itil + itop-welcome-itil + itop-tickets + itop-files-information + combodo-db-tools + itop-core-update + itop-hub-connector + itop-oauth-client + combodo-backoffice-darkmoon-theme + combodo-backoffice-fullmoon-high-contrast-theme + combodo-backoffice-fullmoon-protanopia-deuteranopia-theme + combodo-backoffice-fullmoon-tritanopia-theme + itop-themes-compat + combodo-my-account + combodo-my-account-user-info + combodo-oauth2-client + itop-attribute-class-set + itop-attribute-encrypted-password + itop-ui-copypaste + + true + + + itop-config-mgmt-datacenter + Data Center Devices + Manage Data Center devices such as Racks, Enclosures, PDUs, etc. + + itop-datacenter-mgmt + + true + + + itop-config-mgmt-end-user + End-User Devices + Manage devices related to end-users: PCs, Phones, Tablets, etc. + + itop-endusers-devices + + true + + + itop-config-mgmt-storage + Storage Devices + Manage storage devices such as NAS, SAN Switches, Tape Libraries and Tapes, etc. + + itop-storage-mgmt + + true + + + itop-config-mgmt-virtualization + Virtualization + Manage Hypervisors, Virtual Machines and Farms. + + itop-virtualization-mgmt + + true + + + + itop-container-mgmt + Containerization + + + itop-container-mgmt + + false + + + + + + + + Service Management options + Select the choice that best describes the relationships between the services and the IT infrastructure in your IT environment.]]> + /images/icons/icons8-services.svg + + + itop-service-mgmt-enterprise + Service Management for Enterprises + Select this option if the IT delivers services based on a shared infrastructure. For example if different organizations within your company subscribe to services (like Mail and Print services) delivered by a single shared backend. + + itop-service-mgmt + + true + + + itop-service-mgmt-service-provider + Service Management for Service Providers + Select this option if the IT manages the infrastructure of independent customers. This is the most flexible model, since the services can be delivered with a mix of shared and customer specific infrastructure devices. + + itop-service-mgmt-provider + + + + + + Tickets Management options + Select the type of tickets you want to use in order to respond to user requests and incidents.]]> + /images/icons/icons8-discussion-forum.svg + + + itop-ticket-mgmt-simple-ticket + Simple Ticket Management + Select this option to use one single type of tickets for all kind of requests. + + itop-request-mgmt + + true + + + + itop-ticket-mgmt-simple-ticket-enhanced-portal + Customer Portal + + + itop-portal + itop-portal-base + + true + + + + + + itop-ticket-mgmt-itil + ITIL Compliant Tickets Management + Select this option to have different types of ticket for managing user requests and incidents. Each type of ticket has a specific life cycle and specific fields + + + + itop-ticket-mgmt-itil-user-request + User Request Management + Manage User Request tickets in iTop + + itop-request-mgmt-itil + + + + itop-ticket-mgmt-itil-incident + Incident Management + Manage Incidents tickets in iTop + + itop-incident-mgmt-itil + + + + itop-ticket-mgmt-itil-enhanced-portal + Customer Portal + + + itop-portal + itop-portal-base + + true + + + + + + itop-ticket-mgmt-none + No Tickets Management + Don't manage incidents or user requests in iTop + + + + + + + Change Management options + Select the type of tickets you want to use in order to manage changes to the IT infrastructure.]]> + /images/icons/icons8-change.svg + + + itop-change-mgmt-simple + Simple Change Management + Select this option to use one type of ticket for all kind of changes. + + itop-change-mgmt + + true + + + itop-change-mgmt-itil + ITIL Change Management + Select this option to use Normal/Routine/Emergency change tickets. + + itop-change-mgmt-itil + + + + itop-change-mgmt-none + No Change Management + Don't manage changes in iTop + + + + + + + Additional ITIL tickets + Pick from the list below the additional ITIL processes that are to be implemented in iTop.]]> + /images/icons/icons8-important-book.svg + + + + itop-kown-error-mgmt + Known Errors Management and FAQ + Select this option to track "Known Errors" and FAQs in iTop. + + itop-faq-light + itop-knownerror-mgmt + + + + itop-problem-mgmt + Problem Management + Select this option to track "Problems" in iTop. + + itop-problem-mgmt + + + + + + diff --git a/tests/php-unit-tests/unitary-tests/setup/ressources/datamodels/2.x/itop-config-mgmt/module.itop-config-mgmt.php b/tests/php-unit-tests/unitary-tests/setup/ressources/datamodels/2.x/itop-config-mgmt/module.itop-config-mgmt.php new file mode 100644 index 0000000000..12bea24bd1 --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/ressources/datamodels/2.x/itop-config-mgmt/module.itop-config-mgmt.php @@ -0,0 +1,107 @@ + 'Configuration Management (CMDB)', + 'category' => 'business', + + // Setup + // + 'dependencies' => [ + 'itop-structure/2.7.1', + ], + 'mandatory' => false, + 'visible' => true, + 'installer' => 'ConfigMgmtInstaller', + + // Components + // + 'datamodel' => [ + 'model.itop-config-mgmt.php', + 'main.itop-config-mgmt.php', + ], + 'data.struct' => [ + 'data/en_us.data.itop-brand.xml', + 'data/en_us.data.itop-networkdevicetype.xml', + 'data/en_us.data.itop-osfamily.xml', + 'data/en_us.data.itop-osversion.xml', + ], + 'data.sample' => [ + 'data/data.sample.model.xml', + 'data/data.sample.networkdevicetype.xml', + 'data/data.sample.servers.xml', + 'data/data.sample.nw-devices.xml', + 'data/data.sample.software.xml', + 'data/data.sample.dbserver.xml', + 'data/data.sample.dbschema.xml', + 'data/data.sample.webserver.xml', + 'data/data.sample.webapp.xml', + 'data/data.sample.applications.xml', + 'data/data.sample.applicationsolutionci.xml', + ], + + // Documentation + // + 'doc.manual_setup' => '', + 'doc.more_information' => '', + + // Default settings + // + 'settings' => [ + ], + ] +); + +if (!class_exists('ConfigMgmtInstaller')) { + // Module installation handler + // + class ConfigMgmtInstaller extends ModuleInstallerAPI + { + public static function BeforeWritingConfig(Config $oConfiguration) + { + // If you want to override/force some configuration values, do it here + return $oConfiguration; + } + + /** + * Handler called before creating or upgrading the database schema + * @param $oConfiguration Config The new configuration of the application + * @param $sPreviousVersion string PRevious version number of the module (empty string in case of first install) + * @param $sCurrentVersion string Current version number of the module + */ + public static function BeforeDatabaseCreation(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion) + { + if (strlen($sPreviousVersion) > 0) { + // If you want to migrate data from one format to another, do it here + self::RenameEnumValueInDB('Software', 'type', 'DBserver', 'DBServer'); + self::RenameEnumValueInDB('Software', 'type', 'Webserver', 'WebServer'); + self::RenameEnumValueInDB('Model', 'type', 'SANswitch', 'SANSwitch'); + self::RenameEnumValueInDB('Model', 'type', 'IpPhone', 'IPPhone'); + self::RenameEnumValueInDB('Model', 'type', 'Telephone', 'Phone'); + self::RenameClassInDB('DBserver', 'DBServer'); + self::RenameClassInDB('OSfamily', 'OSFamily'); + self::RenameClassInDB('OSversion', 'OSVersion'); + self::RenameClassInDB('Webserver', 'WebServer'); + self::RenameClassInDB('OSpatch', 'OSPatch'); + self::RenameClassInDB('lnkFunctionalCIToOSpatch', 'lnkFunctionalCIToOSPatch'); + self::RenameClassInDB('OsLicence', 'OSLicence'); + self::RenameClassInDB('IOSversion', 'IOSVersion'); + self::RenameClassInDB('IPinterface', 'IPInterface'); + } + } + + /** + * Handler called after the creation/update of the database schema + * @param $oConfiguration Config The new configuration of the application + * @param $sPreviousVersion string PRevious version number of the module (empty string in case of first install) + * @param $sCurrentVersion string Current version number of the module + */ + public static function AfterDatabaseCreation(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion) + { + } + } +} diff --git a/tests/php-unit-tests/unitary-tests/setup/ressources/datamodels/2.x/itop-service-mgmt/module.itop-service-mgmt.php b/tests/php-unit-tests/unitary-tests/setup/ressources/datamodels/2.x/itop-service-mgmt/module.itop-service-mgmt.php new file mode 100644 index 0000000000..98103251e5 --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/ressources/datamodels/2.x/itop-service-mgmt/module.itop-service-mgmt.php @@ -0,0 +1,89 @@ + 'Service Management', + 'category' => 'business', + + // Setup + // + 'dependencies' => [ + 'itop-tickets/2.0.0', + ], + 'mandatory' => false, + 'visible' => true, + 'installer' => 'ServiceMgmtInstaller', + + // Components + // + 'datamodel' => [ + ], + 'data.struct' => [ + //'data.struct.itop-service-mgmt.xml', + ], + 'data.sample' => [ + 'data/data.sample.organizations.xml', + 'data/data.sample.contracts.xml', + 'data/data.sample.servicefamilies.xml', + 'data/data.sample.services.xml', + 'data/data.sample.serviceelements.xml', + 'data/data.sample.sla.xml', + 'data/data.sample.slt.xml', + 'data/data.sample.sltsla.xml', + // 'data/data.sample.coveragewindows.xml', + 'data/data.sample.contractservice.xml', + // 'data/data.sample.deliverymodel.xml', + 'data/data.sample.deliverymodelcontact.xml', + ], + + // Documentation + // + 'doc.manual_setup' => '', + 'doc.more_information' => '', + + // Default settings + // + 'settings' => [ + ], + ] +); + +if (!class_exists('ServiceMgmtInstaller')) { + // Module installation handler + // + class ServiceMgmtInstaller extends ModuleInstallerAPI + { + public static function BeforeWritingConfig(Config $oConfiguration) + { + // If you want to override/force some configuration values, do it here + return $oConfiguration; + } + + /** + * Handler called before creating or upgrading the database schema + * @param $oConfiguration Config The new configuration of the application + * @param $sPreviousVersion string PRevious version number of the module (empty string in case of first install) + * @param $sCurrentVersion string Current version number of the module + */ + public static function BeforeDatabaseCreation(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion) + { + if (strlen($sPreviousVersion) > 0) { + self::RenameEnumValueInDB('SLT', 'request_type', 'servicerequest', 'service_request'); + } + } + + /** + * Handler called after the creation/update of the database schema + * @param $oConfiguration Config The new configuration of the application + * @param $sPreviousVersion string PRevious version number of the module (empty string in case of first install) + * @param $sCurrentVersion string Current version number of the module + */ + public static function AfterDatabaseCreation(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion) + { + } + } +} diff --git a/tests/php-unit-tests/unitary-tests/setup/ressources/datamodels/2.x/itop-structure/module.itop-structure.php b/tests/php-unit-tests/unitary-tests/setup/ressources/datamodels/2.x/itop-structure/module.itop-structure.php new file mode 100644 index 0000000000..f1da9aeafe --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/ressources/datamodels/2.x/itop-structure/module.itop-structure.php @@ -0,0 +1,449 @@ + 'Core iTop Structure', + 'category' => 'business', + + // Setup + // + 'dependencies' => [ + ], + 'mandatory' => true, + 'visible' => false, + 'installer' => 'StructureInstaller', + + // Components + // + 'datamodel' => [ + 'main.itop-structure.php', + ], + 'data.struct' => [ + ], + 'data.sample' => [ + 'data/data.sample.organizations.xml', + 'data/data.sample.locations.xml', + 'data/data.sample.persons.xml', + 'data/data.sample.teams.xml', + 'data/data.sample.contactteam.xml', + 'data/data.sample.contacttype.xml', + ], + + // Documentation + // + 'doc.manual_setup' => '', + 'doc.more_information' => '', + + // Default settings + // + 'settings' => [ + ], + ] +); + +if (!class_exists('StructureInstaller')) { + // Module installation handler + // + class StructureInstaller extends ModuleInstallerAPI + { + public static function BeforeWritingConfig(Config $oConfiguration) + { + // If you want to override/force some configuration values, do it here + return $oConfiguration; + } + + /** + * Handler called before creating or upgrading the database schema + * @param $oConfiguration Config The new configuration of the application + * @param $sPreviousVersion string PRevious version number of the module (empty string in case of first install) + * @param $sCurrentVersion string Current version number of the module + */ + public static function BeforeDatabaseCreation(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion) + { + if (strlen($sPreviousVersion) > 0) { + // Search for existing ActionEmail where the language attribute was defined on its child + if (version_compare($sPreviousVersion, '3.2.0', '<')) { + SetupLog::Info("| Migrate ActionEmail language attribute values to its parent."); + $sTableToRead = MetaModel::DBGetTable('ActionEmail'); + $sTableToSet = MetaModel::DBGetTable('ActionNotification'); + self::MoveColumnInDB($sTableToRead, 'language', $sTableToSet, 'language', true); + SetupLog::Info("| ActionEmail migration done."); + } + // If you want to migrate data from one format to another, do it here + self::RenameEnumValueInDB('Software', 'type', 'DBserver', 'DBServer'); + self::RenameEnumValueInDB('Software', 'type', 'Webserver', 'WebServer'); + self::RenameEnumValueInDB('Model', 'type', 'SANswitch', 'SANSwitch'); + self::RenameEnumValueInDB('Model', 'type', 'IpPhone', 'IPPhone'); + self::RenameEnumValueInDB('Model', 'type', 'Telephone', 'Phone'); + self::RenameClassInDB('DBserver', 'DBServer'); + self::RenameClassInDB('OSfamily', 'OSFamily'); + self::RenameClassInDB('OSversion', 'OSVersion'); + self::RenameClassInDB('Webserver', 'WebServer'); + self::RenameClassInDB('OSpatch', 'OSPatch'); + self::RenameClassInDB('lnkFunctionalCIToOSpatch', 'lnkFunctionalCIToOSPatch'); + self::RenameClassInDB('OsLicence', 'OSLicence'); + self::RenameClassInDB('IOSversion', 'IOSVersion'); + self::RenameClassInDB('IPinterface', 'IPInterface'); + } + } + + /** + * Handler called after the creation/update of the database schema + * @param $oConfiguration Config The new configuration of the application + * @param $sPreviousVersion string PRevious version number of the module (empty string in case of first install) + * @param $sCurrentVersion string Current version number of the module + */ + public static function AfterDatabaseCreation(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion) + { + // Default language will be used for actions + // Note: There is a issue when upgrading, default language cannot be retrieved from the passed configuration, we have to read it from the disk + if (utils::IsNullOrEmptyString($sPreviousVersion)) { + // Fresh install + $sDefaultLanguage = $oConfiguration->GetDefaultLanguage(); + } else { + // Upgrade + $sDefaultLanguage = utils::GetConfig(true)->GetDefaultLanguage(); + } + // Fallback language on english if not french + $sDefaultLanguage = $sDefaultLanguage === 'FR FR' ? 'FR FR' : 'EN US'; + SetupLog::Info("Default app language used for actions: $sDefaultLanguage"); + + // Search for existing TriggerOnObject where the Trigger string complement is empty and fed it with target_class field value + if (version_compare($sPreviousVersion, '3.1.0', '<')) { + SetupLog::Info("| Feed computed field triggering_class on existing Triggers."); + + $sTableToSet = MetaModel::DBGetTable('Trigger', 'complement'); + $sTableToRead = MetaModel::DBGetTable('TriggerOnObject', 'target_class'); + $oAttDefToSet = MetaModel::GetAttributeDef('Trigger', 'complement'); + $oAttDefToRead = MetaModel::GetAttributeDef('TriggerOnObject', 'target_class'); + + $aColumnsToSets = array_keys($oAttDefToSet->GetSQLColumns()); + $sColumnToSet = $aColumnsToSets[0]; // We know that a string has only one column + $aColumnsToReads = array_keys($oAttDefToRead->GetSQLColumns()); + $sColumnToRead = $aColumnsToReads[0]; // We know that a string has only one column + + $sRepair = "UPDATE $sTableToSet JOIN $sTableToRead ON $sTableToSet.id = $sTableToRead.id SET $sTableToSet.$sColumnToSet = CONCAT('class restriction: ',$sTableToRead.$sColumnToRead) WHERE $sTableToSet.$sColumnToSet = ''"; + SetupLog::Debug(" | | Query: ".$sRepair); + CMDBSource::Query($sRepair); + $iNbProcessed = CMDBSource::AffectedRows(); + SetupLog::Info("| | ".$iNbProcessed." triggers processed."); + } + + // Add notifications by email to Persons if mentioned on any log + if (version_compare($sPreviousVersion, '3.0.0', '<')) { + SetupLog::Info("Adding default triggers/action for Person objects mentions. All DM classes with at least 1 log attribute will be concerned..."); + + $sPersonClass = 'Person'; + $sPersonStateAttCode = MetaModel::GetStateAttributeCode($sPersonClass); + $sPersonOwnerOrgAttCode = UserRightsProfile::GetOwnerOrganizationAttCode($sPersonClass); + + $iClassesWithLogCount = 0; + $aCreatedTriggerIds = []; + foreach (MetaModel::EnumRootClasses() as $sRootClass) { + foreach (MetaModel::EnumChildClasses($sRootClass, ENUM_CHILD_CLASSES_ALL, true) as $sClass) { + $aLogAttCodes = MetaModel::GetAttributesList($sClass, ['AttributeCaseLog']); + + // Skip class with no log attribute + if (count($aLogAttCodes) === 0) { + continue; + } + + // Prepare the mentioned_filter OQL + $oPersonSearch = DBObjectSearch::FromOQL("SELECT $sPersonClass"); + + // - Add status condition if attribute present + if (empty($sPersonStateAttCode) === false) { + $oPersonSearch->AddConditionExpression(new BinaryExpression( + new FieldExpression($sPersonStateAttCode), + '=', + new ScalarExpression('active') + )); + } + + // - Check if the classes have a silo attribute so we can use them in the mentioned_filter + if (empty($sPersonOwnerOrgAttCode) === false) { + // Filter on current contact org. + $oCurrentContactExpr = new BinaryExpression( + new FieldExpression($sPersonOwnerOrgAttCode), + '=', + new VariableExpression("current_contact->org_id") + ); + + // Filter on class owner org. if any + $sClassOwnerOrgAttCode = UserRightsProfile::GetOwnerOrganizationAttCode($sClass); + $oOwnerOrgExpr = empty($sClassOwnerOrgAttCode) ? null : new BinaryExpression( + new FieldExpression($sPersonOwnerOrgAttCode), + '=', + new VariableExpression("this->$sClassOwnerOrgAttCode") + ); + + // No owner org, simple condition + if ($oOwnerOrgExpr === null) { + $oPersonSearch->AddConditionExpression($oCurrentContactExpr); + } + // Owner org, condition is either from owner org or current contact's + else { + $oOrExpr = new BinaryExpression($oCurrentContactExpr, 'OR', $oOwnerOrgExpr); + $oPersonSearch->AddConditionExpression($oOrExpr); + } + } + + // Build the trigger + $oTrigger = MetaModel::NewObject(TriggerOnObjectMention::class); + $oTrigger->Set('description', 'Person mentioned on '.$sClass); + $oTrigger->Set('target_class', $sClass); + $oTrigger->Set('mentioned_filter', $oPersonSearch->ToOQL()); + $oTrigger->DBInsert(); + + SetupLog::Info("|- Created trigger \"{$oTrigger->Get('description')}\" for class $sClass."); + $aCreatedTriggerIds[] = $oTrigger->GetKey(); + $iClassesWithLogCount++; + // Note: We break because we only have to create one trigger/action for the class hierarchy as it will be for all their log attributes + break; + } + } + + // Build the corresponding action and link it to the triggers + if (count($aCreatedTriggerIds) > 0) { + // Actions data for english and french + $aActionsData = [ + 'EN US' => [ + 'name' => 'Notification to persons mentioned in logs', + 'subject' => 'You have been mentioned in "$this->friendlyname$"', + 'body' => '

    Hello $mentioned->first_name$,

    +

    You have been mentioned by $current_contact->friendlyname$ in $this->hyperlink()$

    ', + ], + 'FR FR' => [ + 'name' => 'Notification aux personnes mentionnées dans les journaux', + 'subject' => 'Vous avez été mentionné dans "$this->friendlyname$"', + 'body' => '

    Bonjour $mentioned->first_name$,

    +

    Vous avez été mentionné par $current_contact->friendlyname$ dans $this->hyperlink()$

    ', + ], + ]; + + // Create action in app. default language and link it to the triggers + $aData = $aActionsData[$sDefaultLanguage]; + $oAction = MetaModel::NewObject(ActionEmail::class); + $oAction->Set('name', $aData['name']); + $oAction->Set('status', 'enabled'); + $oAction->Set('language', $sDefaultLanguage); + $oAction->Set('from', '$current_contact->email$'); + $oAction->Set('to', 'SELECT Person WHERE id = :mentioned->id'); + $oAction->Set('subject', $aData['subject']); + $oAction->Set('body', $aData['body']); + + /** @var \ormLinkSet $oOrm */ + $oOrm = $oAction->Get('trigger_list'); + foreach ($aCreatedTriggerIds as $sTriggerId) { + $oLink = new lnkTriggerAction(); + $oLink->Set('trigger_id', $sTriggerId); + $oOrm->AddItem($oLink); + } + $oAction->Set('trigger_list', $oOrm); + $oAction->DBInsert(); + + SetupLog::Info("|- Created action \"{$oAction->Get('name')}\" and linked it to the previously created triggers."); + } + + if ($iClassesWithLogCount === 0) { + SetupLog::Info("... no trigger/action created as there is no DM class with a log attribute."); + } else { + SetupLog::Info("... default triggers/action successfully created for $iClassesWithLogCount classes."); + } + } + + // Add notifications by newsroom to Persons if mentioned on any log + if (version_compare($sPreviousVersion, '3.2.0', '<')) { + SetupLog::Info("Adding default newsroom actions for Person objects mentions. All existing TriggerOnObjectMention mentioning the Person class will be concerned..."); + + $sPersonClass = Person::class; + $iExistingTriggersCount = 0; + + // Actions data for english and french + $aActionsData = [ + 'EN US' => [ + 'name' => 'Notification to persons mentioned in logs', + 'message' => 'You have been mentioned by $current_contact->friendlyname$', + ], + 'FR FR' => [ + 'name' => 'Notification aux personnes mentionnées dans les journaux', + 'message' => 'Vous avez été mentionné par $current_contact->friendlyname$', + ], + ]; + + // Start by creating the default action no matter what (even if there is no relevant trigger, it will be there for future use) + $aData = $aActionsData[$sDefaultLanguage]; + $oAction = MetaModel::NewObject(ActionNewsroom::class); + $oAction->Set('name', $aData['name']); + $oAction->Set('status', 'enabled'); + $oAction->Set('language', $sDefaultLanguage); + $oAction->Set('priority', 3); // Important priority as a mention is probably more important than a simple notification + $oAction->Set('recipients', 'SELECT Person WHERE id = :mentioned->id'); + $oAction->Set('title', '$this->friendlyname$'); + $oAction->Set('message', $aData['message']); + $oAction->DBWrite(); + + SetupLog::Info("|- Created newsroom action \"{$oAction->Get('name')}\"."); + + // Retrieve all triggers and find those with a mentioned_filter on the Person class + $oTriggersSearch = DBObjectSearch::FromOQL("SELECT ".TriggerOnObjectMention::class); + $oTriggersSearch->AllowAllData(); + + $oTriggersSet = new DBObjectSet($oTriggersSearch); + while ($oTrigger = $oTriggersSet->Fetch()) { + // If mentioned class is not a Person, ignore + $oMentionedFilter = DBSearch::FromOQL($oTrigger->Get('mentioned_filter')); + if (!is_null($oMentionedFilter) && is_a($oMentionedFilter->GetClass(), $sPersonClass, true) === false) { + SetupLog::Info("|- Action \"{$oAction->GetName()}\" NOT LINKED to existing trigger \"{$oTrigger->GetName()}\". (mentioned class \"{$oMentionedFilter->GetClass()}\")"); + continue; + } + + // Link the trigger to the action + /** @var \ormLinkSet $oOrm */ + $oOrm = $oTrigger->Get('action_list'); + $oLink = new lnkTriggerAction(); + $oLink->Set('action_id', $oAction->GetKey()); + $oOrm->AddItem($oLink); + + $oTrigger->Set('action_list', $oOrm); + $oTrigger->DBUpdate(); + $iExistingTriggersCount++; + + SetupLog::Info("|- Linked newsroom action \"{$oAction->GetName()}\" to existing trigger \"{$oTrigger->GetName()}\"."); + } + + if ($iExistingTriggersCount === 0) { + SetupLog::Info("... no action created as there is no existing trigger on mention for the $sPersonClass class."); + } else { + SetupLog::Info("... default newsroom action successfully created and linked to $iExistingTriggersCount triggers on mention."); + } + } + + // Force subscription policy to ForceAtLeastOneChannel for all existing TriggerOnObjectMention + if (version_compare($sPreviousVersion, '3.2.0', '<')) { + SetupLog::Info("Forcing subscription policy to ForceAtLeastOneChannel for all existing TriggerOnObjectMention..."); + + $oTriggersSearch = DBObjectSearch::FromOQL("SELECT ".TriggerOnObjectMention::class); + $oTriggersSearch->AllowAllData(); + + $oTriggersSet = new DBObjectSet($oTriggersSearch); + while ($oTrigger = $oTriggersSet->Fetch()) { + $oTrigger->Set('subscription_policy', \Combodo\iTop\Core\Trigger\Enum\SubscriptionPolicy::ForceAtLeastOneChannel->value); + $oTrigger->DBUpdate(); + + SetupLog::Info("|- Trigger \"{$oTrigger->GetName()}\" updated."); + } + + SetupLog::Info("... all existing TriggerOnObjectMention updated."); + } + + // Add notifications by newsroom (not linked to any trigger yet) for TriggerOnPortalUpdate and TriggerOnReachingState + if (version_compare($sPreviousVersion, '3.2.0', '<')) { + // TriggerOnPortalUpdate + SetupLog::Info("Adding default newsroom action for TriggerOnPortalUpdate (not linked to any trigger yet)..."); + + // - Actions data for english and french + $aActionsData = [ + 'EN US' => [ + 'name' => 'Notification on public log update through the portal', + 'message' => 'New message from $current_contact->friendlyname$', + ], + 'FR FR' => [ + 'name' => 'Notification sur MAJ du journal public via le portail', + 'message' => 'Nouveau message de $current_contact->friendlyname$', + ], + ]; + + // - Create action in app. default language and link it to the triggers + $aData = $aActionsData[$sDefaultLanguage]; + $oAction = MetaModel::NewObject(ActionNewsroom::class); + $oAction->Set('name', $aData['name']); + $oAction->Set('status', 'enabled'); + $oAction->Set('language', $sDefaultLanguage); + $oAction->Set('priority', 4); // Standard priority + $oAction->Set('recipients', 'SELECT Person WHERE id = :this->agent_id'); + $oAction->Set('title', '$this->friendlyname$'); + $oAction->Set('message', $aData['message']); + $oAction->DBWrite(); + + // TriggerOnReachingState + SetupLog::Info("Adding default newsroom action for TriggerOnReachingState (not linked to any trigger yet)..."); + + // Actions data for english and french + $aActionsData = [ + 'EN US' => [ + 'name' => 'Notification to agent when ticket assigned', + 'message' => 'Ticket has been assigned to you', + ], + 'FR FR' => [ + 'name' => 'Notification à l\'agent à l\'assignation du ticket', + 'message' => 'Le ticket vous a été assigné', + ], + ]; + + // Create action in app. default language and link it to the triggers + $aData = $aActionsData[$sDefaultLanguage]; + $oAction = MetaModel::NewObject(ActionNewsroom::class); + $oAction->Set('name', $aData['name']); + $oAction->Set('status', 'enabled'); + $oAction->Set('language', $sDefaultLanguage); + $oAction->Set('priority', 3); // Important priority + $oAction->Set('recipients', 'SELECT Person WHERE id = :this->agent_id'); + $oAction->Set('title', '$this->friendlyname$'); + $oAction->Set('message', $aData['message']); + $oAction->DBWrite(); + } + + //N°824 - Fill object_class in EventNotification from the Triggers target_class + if (version_compare($sPreviousVersion, '3.2.0', '<')) { + SetupLog::Info("Filling object_class in EventNotification from the Triggers target_class"); + $iNbProcessed = 0; + + $sTableToSet = MetaModel::DBGetTable('EventNotification', 'object_class'); + $oAttDefToSet = MetaModel::GetAttributeDef('EventNotification', 'object_class'); + $oAttDefObjectId = MetaModel::GetAttributeDef('EventNotification', 'object_id'); + $oAttDefTriggerId = MetaModel::GetAttributeDef('EventNotification', 'trigger_id'); + + $aColumnsToSets = array_keys($oAttDefToSet->GetSQLColumns()); + $sColumnToSet = $aColumnsToSets[0]; // We know that a string has only one column + $aColumnsTriggerId = array_keys($oAttDefTriggerId->GetSQLColumns()); + $sColumnTriggerId = $aColumnsTriggerId[0]; // We know that a string has only one column + $aColumnsObjectd = array_keys($oAttDefObjectId->GetSQLColumns()); + $sColumnObjectId = $aColumnsObjectd[0]; // We know that a string has only one column + + $oSearch = DBObjectSearch::FromOQL('SELECT TriggerOnObject'); + $oSet = new DBObjectSet($oSearch); + $aTriggerIdToTargetClass = []; + while ($oTrigger = $oSet->Fetch()) { + $aTriggerIdToTargetClass[$oTrigger->GetKey()] = $oTrigger->Get('target_class'); + } + + foreach ($aTriggerIdToTargetClass as $sKey => $sTargetClass) { + + if (MetaModel::HasChildrenClasses($sTargetClass)) { + //in this case, we have toget the name of the final class + $sTableToRead = MetaModel::DBGetTable($sTargetClass, 'finalclass'); + $oAttDefToRead = MetaModel::GetAttributeDef($sTargetClass, 'finalclass'); + $aColumnsToReads = array_keys($oAttDefToRead->GetSQLColumns()); + $sColumnToRead = $aColumnsToReads[0]; // We know that a string has only one column + $sObjectPrimaryKey = MetaModel::DBGetKey($sTargetClass); + + $sRepair = "UPDATE `$sTableToSet` JOIN `$sTableToRead` ON `$sTableToSet`.`$sColumnObjectId` = `$sTableToRead`.`$sObjectPrimaryKey` SET `$sTableToSet`.`$sColumnToSet` = `$sTableToRead`.`$sColumnToRead` WHERE `$sTableToSet`.`$sColumnTriggerId` = '".$sKey."' AND `$sTableToSet`.`$sColumnToSet` = ''"; + } else { + + $sRepair = "UPDATE `$sTableToSet` SET `$sTableToSet`.`$sColumnToSet` = '".$sTargetClass."' WHERE `$sTableToSet`.`$sColumnTriggerId` = '".$sKey."' AND `$sTableToSet`.`$sColumnToSet` = ''"; + } + + SetupLog::Info(" | | Query: ".$sRepair); + CMDBSource::Query($sRepair); + $iNbProcessed += CMDBSource::AffectedRows(); + } + SetupLog::Info("| | ".$iNbProcessed." EventNotification processed."); + } + } + } +} diff --git a/tests/php-unit-tests/unitary-tests/setup/ressources/installation.xml b/tests/php-unit-tests/unitary-tests/setup/ressources/installation.xml new file mode 100644 index 0000000000..4a7c6bd004 --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/ressources/installation.xml @@ -0,0 +1,216 @@ + + + + + Configuration Management options + The options below allow you to configure the type of elements that are to be managed inside iTop.]]> + /images/modules.png + + + itop-config-mgmt-core + Configuration Management Core + All the base objects that are mandatory in the iTop CMDB: Organizations, Locations, Teams, Persons, etc. + + itop-config-mgmt + itop-attachments + itop-profiles-itil + itop-welcome-itil + itop-tickets + itop-files-information + combodo-db-tools + itop-core-update + itop-hub-connector + itop-oauth-client + + true + + + itop-config-mgmt-datacenter + Data Center Devices + Manage Data Center devices such as Racks, Enclosures, PDUs, etc. + + itop-datacenter-mgmt + + true + + + itop-config-mgmt-end-user + End-User Devices + Manage devices related to end-users: PCs, Phones, Tablets, etc. + + itop-endusers-devices + + true + + + itop-config-mgmt-storage + Storage Devices + Manage storage devices such as NAS, SAN Switches, Tape Libraries and Tapes, etc. + + itop-storage-mgmt + + true + + + itop-config-mgmt-virtualization + Virtualization + Manage Hypervisors, Virtual Machines and Farms. + + itop-virtualization-mgmt + + true + + + + + Service Management options + Select the choice that best describes the relationships between the services and the IT infrastructure in your IT environment.]]> + ./wizard-icons/service.png + + + itop-service-mgmt-enterprise + Service Management for Enterprises + Select this option if the IT delivers services based on a shared infrastructure. For example if different organizations within your company subscribe to services (like Mail and Print services) delivered by a single shared backend. + + itop-service-mgmt + + true + + + itop-service-mgmt-service-provider + Service Management for Service Providers + Select this option if the IT manages the infrastructure of independent customers. This is the most flexible model, since the services can be delivered with a mix of shared and customer specific infrastructure devices. + + itop-service-mgmt-provider + + + + + + Tickets Management options + Select the type of tickets you want to use in order to respond to user requests and incidents.]]> + ./itop-incident-mgmt-itil/images/incident-escalated.svg + + + itop-ticket-mgmt-simple-ticket + Simple Ticket Management + Select this option to use one single type of tickets for all kind of requests. + + itop-request-mgmt + + true + + + + itop-ticket-mgmt-simple-ticket-enhanced-portal + Customer Portal + + + itop-portal + itop-portal-base + + true + + + + + + itop-ticket-mgmt-itil + ITIL Compliant Tickets Management + Select this option to have different types of ticket for managing user requests and incidents. Each type of ticket has a specific life cycle and specific fields + + + + itop-ticket-mgmt-itil-user-request + User Request Management + Manage User Request tickets in iTop + + itop-request-mgmt-itil + + + + itop-ticket-mgmt-itil-incident + Incident Management + Manage Incidents tickets in iTop + + itop-incident-mgmt-itil + + + + itop-ticket-mgmt-itil-enhanced-portal + Customer Portal + + + itop-portal + itop-portal-base + + true + + + + + + itop-ticket-mgmt-none + No Tickets Management + Don't manage incidents or user requests in iTop + + + + + + + Change Management options + Select the type of tickets you want to use in order to manage changes to the IT infrastructure.]]> + ./itop-change-mgmt/images/change.svg + + + itop-change-mgmt-simple + Simple Change Management + Select this option to use one type of ticket for all kind of changes. + + itop-change-mgmt + + true + + + itop-change-mgmt-itil + ITIL Change Management + Select this option to use Normal/Routine/Emergency change tickets. + + itop-change-mgmt-itil + + + + itop-change-mgmt-none + No Change Management + Don't manage changes in iTop + + + + + + + Additional ITIL tickets + Pick from the list below the additional ITIL processes that are to be implemented in iTop.]]> + ./itop-knownerror-mgmt/images/known-error.svg + + + itop-kown-error-mgmt + Known Errors Management + Select this option to track "Known Errors" and FAQs in iTop. + + itop-knownerror-mgmt + + + + itop-problem-mgmt + Problem Management + Select this option to track "Problems" in iTop. + + itop-problem-mgmt + + + + + + diff --git a/tests/php-unit-tests/unitary-tests/setup/ressources/installation_330.xml b/tests/php-unit-tests/unitary-tests/setup/ressources/installation_330.xml new file mode 100644 index 0000000000..82f159e521 --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/ressources/installation_330.xml @@ -0,0 +1,243 @@ + + + + + Configuration Management options + The options below allow you to configure the type of elements that are to be managed inside iTop.]]> + /images/icons/icons8-apps-tab.svg + + + itop-config-mgmt-core + Configuration Management Core + All the base objects that are mandatory in the iTop CMDB: Organizations, Locations, Teams, Persons, etc. + + itop-structure + itop-config-mgmt + itop-attachments + itop-profiles-itil + itop-welcome-itil + itop-tickets + itop-files-information + combodo-db-tools + itop-core-update + itop-hub-connector + itop-oauth-client + combodo-backoffice-darkmoon-theme + combodo-backoffice-fullmoon-high-contrast-theme + combodo-backoffice-fullmoon-protanopia-deuteranopia-theme + combodo-backoffice-fullmoon-tritanopia-theme + itop-themes-compat + combodo-my-account + combodo-my-account-user-info + combodo-oauth2-client + itop-attribute-class-set + itop-attribute-encrypted-password + itop-ui-copypaste + + true + + + itop-config-mgmt-datacenter + Data Center Devices + Manage Data Center devices such as Racks, Enclosures, PDUs, etc. + + itop-datacenter-mgmt + + true + + + itop-config-mgmt-end-user + End-User Devices + Manage devices related to end-users: PCs, Phones, Tablets, etc. + + itop-endusers-devices + + true + + + itop-config-mgmt-storage + Storage Devices + Manage storage devices such as NAS, SAN Switches, Tape Libraries and Tapes, etc. + + itop-storage-mgmt + + true + + + itop-config-mgmt-virtualization + Virtualization + Manage Hypervisors, Virtual Machines and Farms. + + itop-virtualization-mgmt + + true + + + + itop-container-mgmt + Containerization + + + itop-container-mgmt + + false + + + + + + + + Service Management options + Select the choice that best describes the relationships between the services and the IT infrastructure in your IT environment.]]> + /images/icons/icons8-services.svg + + + itop-service-mgmt-enterprise + Service Management for Enterprises + Select this option if the IT delivers services based on a shared infrastructure. For example if different organizations within your company subscribe to services (like Mail and Print services) delivered by a single shared backend. + + itop-service-mgmt + + true + + + itop-service-mgmt-service-provider + Service Management for Service Providers + Select this option if the IT manages the infrastructure of independent customers. This is the most flexible model, since the services can be delivered with a mix of shared and customer specific infrastructure devices. + + itop-service-mgmt-provider + + + + + + Tickets Management options + Select the type of tickets you want to use in order to respond to user requests and incidents.]]> + /images/icons/icons8-discussion-forum.svg + + + itop-ticket-mgmt-simple-ticket + Simple Ticket Management + Select this option to use one single type of tickets for all kind of requests. + + itop-request-mgmt + + true + + + + itop-ticket-mgmt-simple-ticket-enhanced-portal + Customer Portal + + + itop-portal + itop-portal-base + + true + + + + + + itop-ticket-mgmt-itil + ITIL Compliant Tickets Management + Select this option to have different types of ticket for managing user requests and incidents. Each type of ticket has a specific life cycle and specific fields + + + + itop-ticket-mgmt-itil-user-request + User Request Management + Manage User Request tickets in iTop + + itop-request-mgmt-itil + + + + itop-ticket-mgmt-itil-incident + Incident Management + Manage Incidents tickets in iTop + + itop-incident-mgmt-itil + + + + itop-ticket-mgmt-itil-enhanced-portal + Customer Portal + + + itop-portal + itop-portal-base + + true + + + + + + itop-ticket-mgmt-none + No Tickets Management + Don't manage incidents or user requests in iTop + + + + + + + Change Management options + Select the type of tickets you want to use in order to manage changes to the IT infrastructure.]]> + /images/icons/icons8-change.svg + + + itop-change-mgmt-simple + Simple Change Management + Select this option to use one type of ticket for all kind of changes. + + itop-change-mgmt + + true + + + itop-change-mgmt-itil + ITIL Change Management + Select this option to use Normal/Routine/Emergency change tickets. + + itop-change-mgmt-itil + + + + itop-change-mgmt-none + No Change Management + Don't manage changes in iTop + + + + + + + Additional ITIL tickets + Pick from the list below the additional ITIL processes that are to be implemented in iTop.]]> + /images/icons/icons8-important-book.svg + + + + itop-kown-error-mgmt + Known Errors Management and FAQ + Select this option to track "Known Errors" and FAQs in iTop. + + itop-faq-light + itop-knownerror-mgmt + + + + itop-problem-mgmt + Problem Management + Select this option to track "Problems" in iTop. + + itop-problem-mgmt + + + + + + diff --git a/tests/php-unit-tests/unitary-tests/setup/sequencers/ApplicationInstallerSequencerTest.php b/tests/php-unit-tests/unitary-tests/setup/sequencers/ApplicationInstallerSequencerTest.php new file mode 100644 index 0000000000..ed4d706577 --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/sequencers/ApplicationInstallerSequencerTest.php @@ -0,0 +1,534 @@ +RequireOnceItopFile('/setup/sequencers/ApplicationInstallSequencer.php'); + $this->RequireOnceItopFile('/setup/sequencers/DataAuditSequencer.php'); + $this->RequireOnceItopFile('/setup/parameters.class.inc.php'); + $this->RequireOnceItopFile('/setup/setuputils.class.inc.php'); + $this->RequireOnceItopFile('/setup/runtimeenv.class.inc.php'); + } + + public static function FirstStepProvider() + { + return [ + 'next is db-update' => [ + 'next-step' => 'db-schema', + 'next-step-label' => 'Updating database schema', + 'prev-step-success-message' => '', + 'percentage-completed' => 16, + 'optional_steps' => [], + ], + 'next is log-parameters' => [ + 'next-step' => 'log-parameters', + 'next-step-label' => 'Log parameters', + 'prev-step-success-message' => '', + 'percentage-completed' => 11, + 'optional_steps' => [ + 'log-parameters' => true, + 'backup' => true, + 'migrate-before' => true, + ], + ], + 'next is backup' => [ + 'next-step' => 'backup', + 'next-step-label' => 'Performing a backup of the database', + 'prev-step-success-message' => '', + 'percentage-completed' => 12, + 'optional_steps' => [ + 'backup' => true, + 'migrate-before' => true, + ], + ], + 'next is migrate-before' => [ + 'next-step' => 'migrate-before', + 'next-step-label' => 'Migrate data before database upgrade', + 'prev-step-success-message' => '', + 'percentage-completed' => 14, + 'optional_steps' => [ + 'migrate-before' => true, + ], + 'bCallEnterMaintenanceMode' => true, + ], + ]; + } + + /** + * @dataProvider FirstStepProvider + */ + public function testFirstStep($sNextStep, $sNextLabel, $sPrevStepSuccessMessage, $iPercent, $aOptionalSteps, bool $bCallEnterMaintenanceMode = false, bool $bCallExitMaintenanceMode = false) + { + $aAdditionalParams = [ + 'optional_steps' => $aOptionalSteps, + ]; + $this->GivenApplicationInstallSequencer($aAdditionalParams, $bCallEnterMaintenanceMode, $bCallExitMaintenanceMode); + + $aRes = $this->oSequencer->ExecuteStep(); + $aExpected = [ + 'status' => 1, + 'message' => '', + 'next-step' => $sNextStep, + 'next-step-label' => $sNextLabel, + 'prev-step-success-message' => $sPrevStepSuccessMessage, + 'percentage-completed' => $iPercent, + ]; + $this->assertEquals($aExpected, $aRes); + } + + public function testLogStep() + { + $this->GivenApplicationInstallSequencer(); + + $aRes = $this->oSequencer->ExecuteStep('log-parameters'); + $aExpected = [ + 'status' => 1, + 'message' => '', + 'next-step' => 'db-schema', + 'next-step-label' => 'Updating database schema', + 'prev-step-success-message' => 'Parameters logged', + 'percentage-completed' => 16, + ]; + $this->assertEquals($aExpected, $aRes); + } + + public static function BackupStepProvider() + { + return [ + 'next is db-update' => [ + 'next-step' => 'db-schema', + 'next-step-label' => 'Updating database schema', + 'prev-step-success-message' => 'Database backup completed', + 'percentage-completed' => 28, + 'optional_steps' => [ + 'backup' => true, + ], + ], + 'next is migrate-before' => [ + 'next-step' => 'migrate-before', + 'next-step-label' => 'Migrate data before database upgrade', + 'prev-step-success-message' => 'Database backup completed', + 'percentage-completed' => 25, + 'optional_steps' => [ + 'backup' => true, + 'migrate-before' => true, + ], + ], + ]; + } + + /** + * @dataProvider BackupStepProvider + */ + public function testBackup($sNextStep, $sNextLabel, $sPrevStepSuccessMessage, $iPercent, $aOptionalSteps) + { + $aAdditionalParams = [ + 'optional_steps' => $aOptionalSteps, + ]; + $aAdditionalParams['optional_steps']['backup'] = [ + 'destination' => '/my_backup_file_path', + 'configuration_file' => '/my_config_file_path', + ]; + + $this->GivenApplicationInstallSequencer($aAdditionalParams); + $this->oRunTimeEnvironment->expects($this->once())->method('Backup') + ->with($this->oConfig, '/my_backup_file_path', '/my_config_file_path', null); + + $aRes = $this->oSequencer->ExecuteStep('backup'); + $aExpected = [ + 'status' => 1, + 'message' => '', + 'next-step' => $sNextStep, + 'next-step-label' => $sNextLabel, + 'prev-step-success-message' => $sPrevStepSuccessMessage, + 'percentage-completed' => $iPercent, + ]; + $this->assertEquals($aExpected, $aRes); + } + + public function testMigrateBefore() + { + $aAdditionalParams = [ + 'optional_steps' => [ + 'migrate-before' => true, + ], + ]; + $this->GivenApplicationInstallSequencer($aAdditionalParams, bCallEnterMaintenanceMode: true); + + $this->oRunTimeEnvironment->expects($this->once())->method('MigrateDataBeforeUpdateStructure') + ->with('install', $this->oConfig); + + $aRes = $this->oSequencer->ExecuteStep('migrate-before'); + $aExpected = [ + 'status' => 1, + 'message' => '', + 'next-step' => 'db-schema', + 'next-step-label' => 'Updating database schema', + 'prev-step-success-message' => 'Pre-upgrade data migration completed', + 'percentage-completed' => 28, + ]; + $this->assertEquals($aExpected, $aRes); + } + + public static function DbUpdateStepProvider() + { + return [ + 'next is migrate-after' => [ + 'next-step' => 'migrate-after', + 'next-step-label' => 'Migrate data after database upgrade', + 'prev-step-success-message' => 'Database schema updated', + 'percentage-completed' => 28, + 'optional_steps' => [ + 'migrate-after' => true, + ], + ], + 'next is after-db-create' => [ + 'next-step' => 'after-db-create', + 'next-step-label' => 'Load data after database create', + 'prev-step-success-message' => 'Database schema updated', + 'percentage-completed' => 33, + 'optional_steps' => [], + ], + ]; + } + + /** + * @dataProvider DbUpdateStepProvider + */ + public function testDbUpdate($sNextStep, $sNextLabel, $sPrevStepSuccessMessage, $iPercent, $aOptionalSteps) + { + $aAdditionalParams = [ + 'selected_modules' => ["a" => "b"], + 'optional_steps' => $aOptionalSteps, + ]; + $this->GivenApplicationInstallSequencer($aAdditionalParams); + + $this->oRunTimeEnvironment->expects($this->once())->method('UpdateDBSchema') + ->with($this->oConfig, 'install', ["a" => "b"]); + $this->oRunTimeEnvironment->expects($this->once())->method('SetDbUUID') + ->with(); + + $aRes = $this->oSequencer->ExecuteStep('db-schema'); + $aExpected = [ + 'status' => 1, + 'message' => '', + 'next-step' => $sNextStep, + 'next-step-label' => $sNextLabel, + 'prev-step-success-message' => $sPrevStepSuccessMessage, + 'percentage-completed' => $iPercent, + ]; + $this->assertEquals($aExpected, $aRes); + } + + public function testMigrateAfter() + { + $aAdditionalParams = [ + 'optional_steps' => [ + 'migrate-after' => true, + ], + ]; + $this->GivenApplicationInstallSequencer($aAdditionalParams); + + $this->oRunTimeEnvironment->expects($this->once())->method('MigrateDataAfterUpdateStructure') + ->with('install', $this->oConfig); + + $aRes = $this->oSequencer->ExecuteStep('migrate-after'); + $aExpected = [ + 'status' => 1, + 'message' => '', + 'next-step' => 'after-db-create', + 'next-step-label' => 'Load data after database create', + 'prev-step-success-message' => 'Post-upgrade data migration completed', + 'percentage-completed' => 42, + ]; + $this->assertEquals($aExpected, $aRes); + } + + public function testAfterDbCreate() + { + $aAdminParams = [ + 'user' => "ga", + 'pwd' => "zo", + 'language' => "meu", + ]; + $aAdditionalParams = [ + 'selected_modules' => ["a" => "b"], + 'admin_account' => $aAdminParams, + ]; + $this->GivenApplicationInstallSequencer($aAdditionalParams); + + $this->oRunTimeEnvironment->expects($this->once())->method('AfterDBCreate') + ->with($this->oConfig, 'install', ["a" => "b"], $aAdminParams); + + $aRes = $this->oSequencer->ExecuteStep('after-db-create'); + $aExpected = [ + 'status' => 1, + 'message' => '', + 'next-step' => 'load-data', + 'next-step-label' => 'Loading data', + 'prev-step-success-message' => 'Post-creation data loaded', + 'percentage-completed' => 50, + ]; + $this->assertEquals($aExpected, $aRes); + } + + public function testLoadData() + { + $aAdditionalParams = [ + 'selected_modules' => ["a" => "b"], + 'sample_data' => 1, + ]; + $this->GivenApplicationInstallSequencer($aAdditionalParams); + + $this->oRunTimeEnvironment->expects($this->once())->method('DoLoadData') + ->with($this->oConfig, true, ["a" => "b"]); + + $aRes = $this->oSequencer->ExecuteStep('load-data'); + $aExpected = [ + 'message' => '', + 'next-step' => 'create-config', + 'next-step-label' => 'Creating the configuration File', + 'prev-step-success-message' => 'Data loaded', + 'percentage-completed' => 66, + 'status' => 1, + ]; + $this->assertEquals($aExpected, $aRes); + } + + public function testCreateConfig() + { + $aAdditionalParams = [ + 'datamodel_version' => "6.6.6", + 'selected_extensions' => ["c" => "d"], + 'selected_modules' => ["a" => "b"], + 'sample_data' => 1, + ]; + $this->GivenApplicationInstallSequencer($aAdditionalParams); + $this->oRunTimeEnvironment->expects($this->once())->method('DoCreateConfig') + ->with($this->oConfig, "6.6.6", ["a" => "b"], ["c" => "d"], null); + + $aRes = $this->oSequencer->ExecuteStep('create-config'); + $aExpected = [ + 'message' => '', + 'next-step' => 'commit', + 'next-step-label' => 'Finalize', + 'prev-step-success-message' => 'Configuration file created', + 'percentage-completed' => 83, + 'status' => 1, + ]; + $this->assertEquals($aExpected, $aRes); + } + + public function testCommit() + { + $this->GivenApplicationInstallSequencer(bCallExitMaintenanceMode: true); + $this->oRunTimeEnvironment->expects($this->once())->method('Commit'); + $this->oRunTimeEnvironment->expects($this->once())->method('ExitReadOnlyMode'); + + $aRes = $this->oSequencer->ExecuteStep('commit'); + $aExpected = [ + 'message' => '', + 'next-step' => '', + 'next-step-label' => 'Completed', + 'prev-step-success-message' => '', + 'percentage-completed' => 100, + 'status' => 1, + ]; + $this->assertEquals($aExpected, $aRes); + } + + public function testAnyFailure() + { + $this->GivenApplicationInstallSequencer(); + $this->oRunTimeEnvironment->expects($this->once())->method('GetBuildEnv') + ->willThrowException(new \CoreException('SHADOK MSG')); + + $aRes = $this->oSequencer->ExecuteStep('db-schema'); + $aExpected = [ + 'status' => 2, + 'message' => 'SHADOK MSG', + 'next-step' => '', + 'next-step-label' => '', + 'prev-step-success-message' => '', + 'percentage-completed' => 100, + 'error_code' => 0, + ]; + $this->assertEquals($aExpected, $aRes); + } + + public function testUnknownStep() + { + $this->GivenApplicationInstallSequencer(); + $aRes = $this->oSequencer->ExecuteStep('gabuzomeu'); + $aExpected = [ + 'status' => 2, + 'message' => '', + 'next-step' => '', + 'next-step-label' => 'Unknown setup step \'gabuzomeu\'.', + 'prev-step-success-message' => '', + 'percentage-completed' => 100, + ]; + $this->assertEquals($aExpected, $aRes); + } + + private function GivenParams(array $aAdditionalParams = []): PHPParameters + { + $oParams = new PHPParameters(); + $aParams = array_merge_recursive([ + 'mode' => 'install', + 'database' => [ + 'server' => 'server', + 'user' => 'user', + 'pwd' => 'pwd', + 'name' => 'name', + 'prefix' => 'prefix', + 'db_tls_enabled' => 'db_tls_enabled', + 'db_tls_ca' => 'db_tls_ca', + ], + 'application_path' => '', + 'language' => '', + 'graphviz_path' => '', + 'source_dir' => '', + ], $aAdditionalParams); + + $oParams->LoadFromHash($aParams); + return $oParams; + } + + public function testGetStepNamesWithAllSteps() + { + $aAdditionalParams = [ + 'optional_steps' => [ + 'log-parameters' => true, + 'backup' => true, + 'migrate-before' => true, + 'migrate-after' => true, + ], + ]; + $this->GivenApplicationInstallSequencer($aAdditionalParams, true); + + $expected = [ + '', + 'log-parameters', + 'backup', + 'migrate-before', + 'db-schema', + 'migrate-after', + 'after-db-create', + 'load-data', + 'create-config', + 'commit', + ]; + $this->assertEquals($expected, $this->oSequencer->GetStepNames()); + } + + public static function WithoutOneStepProvider() + { + return [ + ['log-parameters'], + ['backup'], + ['migrate-before'], + ['migrate-after'], + ]; + } + /** + * @dataProvider WithoutOneStepProvider + */ + public function testAllWithoutOneStep($sMissingStepName) + { + $aAdditionalParams = [ + 'optional_steps' => [ + 'log-parameters' => true, + 'backup' => true, + 'migrate-before' => true, + 'migrate-after' => true, + ], + ]; + unset($aAdditionalParams['optional_steps'][$sMissingStepName]); + $this->GivenApplicationInstallSequencer($aAdditionalParams, true); + + $expected = [ + '' => true, + 'log-parameters' => true, + 'backup' => true, + 'migrate-before' => true, + 'db-schema' => true, + 'migrate-after' => true, + 'after-db-create' => true, + 'load-data' => true, + 'create-config' => true, + 'commit' => true, + ]; + unset($expected[$sMissingStepName]); + $this->assertEquals(array_keys($expected), $this->oSequencer->GetStepNames()); + } + + public function testGetStepNamesWithOnlyMandatorySteps() + { + $this->GivenApplicationInstallSequencer([], true); + $expected = [ + '', + 'db-schema', + 'after-db-create', + 'load-data', + 'create-config', + 'commit', + ]; + $this->assertEquals($expected, $this->oSequencer->GetStepNames()); + } + + public function testGetStepAfterWithPercent() + { + $this->GivenApplicationInstallSequencer([], true); + $this->assertEquals(['db-schema', 16], $this->oSequencer->GetStepAfterWithPercent('')); + $this->assertEquals(['after-db-create', 33], $this->oSequencer->GetStepAfterWithPercent('db-schema')); + $this->assertEquals(['load-data', 50], $this->oSequencer->GetStepAfterWithPercent('after-db-create')); + $this->assertEquals(['create-config', 66], $this->oSequencer->GetStepAfterWithPercent('load-data')); + $this->assertEquals(['commit', 83], $this->oSequencer->GetStepAfterWithPercent('create-config')); + $this->assertEquals(['', 100], $this->oSequencer->GetStepAfterWithPercent('commit')); + } + + private function GivenRunTimeEnvironment(bool $bStepComputationOnly = false, bool $bCallEnterMaintenanceMode = false, bool $bCallExitMaintenanceMode = false): void + { + $this->oRunTimeEnvironment = $this->createMock(RunTimeEnvironment::class); + if (! $bStepComputationOnly) { + $this->oRunTimeEnvironment->expects($this->once())->method('EnterReadOnlyMode') + ->with($this->oConfig); + } + + $this->oRunTimeEnvironment->expects($this->exactly($bCallEnterMaintenanceMode ? 1 : 0))->method('EnterMaintenanceMode') + ->with($this->oConfig); + + $this->oRunTimeEnvironment->expects($this->exactly($bCallExitMaintenanceMode ? 1 : 0))->method('ExitMaintenanceMode'); + } + + private function GivenConfig(): void + { + $this->oConfig = $this->createMock(Config::class); + } + + private function GivenApplicationInstallSequencer(array $aAdditionalParams = [], bool $bStepComputationOnly = false, bool $bCallEnterMaintenanceMode = false, bool $bCallExitMaintenanceMode = false): void + { + $this->GivenConfig(); + $this->GivenRunTimeEnvironment($bStepComputationOnly, $bCallEnterMaintenanceMode, $bCallExitMaintenanceMode); + $this->oSequencer = new ApplicationInstallSequencer($this->GivenParams($aAdditionalParams), $this->oRunTimeEnvironment); + $this->SetNonPublicProperty($this->oSequencer, 'oTestConfig', $this->oConfig); + } +} diff --git a/tests/php-unit-tests/unitary-tests/setup/sequencers/DataAuditSequencerTest.php b/tests/php-unit-tests/unitary-tests/setup/sequencers/DataAuditSequencerTest.php new file mode 100644 index 0000000000..97dc0bac9a --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/setup/sequencers/DataAuditSequencerTest.php @@ -0,0 +1,390 @@ +RequireOnceItopFile('/setup/sequencers/ApplicationInstallSequencer.php'); + $this->RequireOnceItopFile('/setup/sequencers/DataAuditSequencer.php'); + $this->RequireOnceItopFile('/setup/parameters.class.inc.php'); + $this->RequireOnceItopFile('/setup/setuputils.class.inc.php'); + $this->RequireOnceItopFile('/setup/runtimeenv.class.inc.php'); + } + + public function testDataAuditFirstStep() + { + $oRunTimeEnvironment = $this->createMock(\RunTimeEnvironment::class); + $oRunTimeEnvironment->expects($this->once())->method('GetBuildEnv') + ->willReturn('production-test'); + $oSequencer = new DataAuditSequencer($this->GivenParams(), $oRunTimeEnvironment); + + $aRes = $oSequencer->ExecuteStep(); + $aExpected = [ + 'status' => 1, + 'message' => '', + 'next-step' => 'copy', + 'next-step-label' => 'Copying data model files', + 'prev-step-success-message' => '', + 'percentage-completed' => 25, + ]; + $this->assertEquals($aExpected, $aRes); + } + + public function testDataUnknownStep() + { + $oRunTimeEnvironment = $this->createMock(\RunTimeEnvironment::class); + $oRunTimeEnvironment->expects($this->once())->method('GetBuildEnv') + ->willReturn('production-test'); + $oSequencer = new DataAuditSequencer($this->GivenParams(), $oRunTimeEnvironment); + + $aRes = $oSequencer->ExecuteStep('gabuzomeu'); + $aExpected = [ + 'status' => 2, + 'message' => '', + 'next-step' => '', + 'next-step-label' => 'Unknown setup step \'gabuzomeu\'.', + 'prev-step-success-message' => '', + 'percentage-completed' => 100, + ]; + $this->assertEquals($aExpected, $aRes); + } + + public function testCopy() + { + $oRunTimeEnvironment = $this->createMock(\RunTimeEnvironment::class); + $oRunTimeEnvironment->expects($this->once())->method('CopySetupFiles'); + $oSequencer = new DataAuditSequencer($this->GivenParams(), $oRunTimeEnvironment); + + $aRes = $oSequencer->ExecuteStep('copy'); + $aExpected = [ + 'status' => 1, + 'message' => '', + 'next-step' => 'compile', + 'next-step-label' => 'Compiling the data model', + 'prev-step-success-message' => 'Data model files copied', + 'percentage-completed' => 50, + ]; + $this->assertEquals($aExpected, $aRes); + } + + public function testCompileWithAudit() + { + $oRunTimeEnvironment = $this->createMock(\RunTimeEnvironment::class); + $oRunTimeEnvironment->expects($this->once())->method('GetApplicationVersion') + ->willReturn(['product_version' => ITOP_VERSION_FULL]); + $oRunTimeEnvironment->expects($this->once())->method('DoCompile'); + $oRunTimeEnvironment->expects($this->once())->method('GetFinalEnv') + ->willReturn('production'); + + $aAdditionalParams = [ + 'mode' => 'update', + 'optional_steps' => ['setup-audit' => true ], + ]; + $oSequencer = new DataAuditSequencer($this->GivenParams($aAdditionalParams), $oRunTimeEnvironment); + + $aRes = $oSequencer->ExecuteStep('compile'); + $aExpected = [ + 'status' => 1, + 'message' => '', + 'next-step' => 'setup-audit', + 'next-step-label' => 'Checking data consistency with the new data model', + 'prev-step-success-message' => 'Data model compilation completed', + 'percentage-completed' => 50, + ]; + $this->assertEquals($aExpected, $aRes); + } + + public function testCompileWithAuditDisabledViaOptionalSteps() + { + $oRunTimeEnvironment = $this->createMock(\RunTimeEnvironment::class); + $oRunTimeEnvironment->expects($this->never())->method('GetApplicationVersion'); + $oRunTimeEnvironment->expects($this->once())->method('DoCompile'); + $oRunTimeEnvironment->expects($this->never())->method('GetFinalEnv') + ->willReturn('production'); + + $aAdditionalParams = [ + 'mode' => 'update', + ]; + $oSequencer = new DataAuditSequencer($this->GivenParams($aAdditionalParams), $oRunTimeEnvironment); + + $aRes = $oSequencer->ExecuteStep('compile'); + $aExpected = [ + 'status' => 1, + 'message' => '', + 'next-step' => 'complete', + 'next-step-label' => 'Check Completed', + 'prev-step-success-message' => 'Data model compilation completed', + 'percentage-completed' => 75, + ]; + $this->assertEquals($aExpected, $aRes); + } + + public function testCompileNoAuditInFreshInstall() + { + $oRunTimeEnvironment = $this->createMock(\RunTimeEnvironment::class); + $oRunTimeEnvironment->expects($this->once())->method('DoCompile'); + $oSequencer = new DataAuditSequencer($this->GivenParams(), $oRunTimeEnvironment); + + $aRes = $oSequencer->ExecuteStep('compile'); + $aExpected = [ + 'status' => 1, + 'message' => '', + 'next-step' => 'complete', + 'next-step-label' => 'Check Completed', + 'prev-step-success-message' => 'Data model compilation completed', + 'percentage-completed' => 75, + ]; + $this->assertEquals($aExpected, $aRes); + } + + public function testCompileNoAuditInUpgradeWithoutAnyRuntimeEnv() + { + $oRunTimeEnvironment = $this->createMock(\RunTimeEnvironment::class); + $oRunTimeEnvironment->expects($this->once())->method('GetApplicationVersion') + ->willReturn(['product_version' => ITOP_VERSION_FULL]); + $oRunTimeEnvironment->expects($this->once())->method('DoCompile'); + $oRunTimeEnvironment->expects($this->once())->method('GetFinalEnv') + ->willReturn('gabuzomeu'); + + $aAdditionalParams = [ + 'mode' => 'update', + 'optional_steps' => ['setup-audit' => true ], + ]; + $oSequencer = new DataAuditSequencer($this->GivenParams($aAdditionalParams), $oRunTimeEnvironment); + + $aRes = $oSequencer->ExecuteStep('compile'); + $aExpected = [ + 'status' => 1, + 'message' => '', + 'next-step' => 'complete', + 'next-step-label' => 'Check Completed', + 'prev-step-success-message' => 'Data model compilation completed', + 'percentage-completed' => 66, + ]; + $this->assertEquals($aExpected, $aRes); + } + + public function testCompileFailureInFreshInstallNoAudit() + { + $oRunTimeEnvironment = $this->createMock(\RunTimeEnvironment::class); + $oRunTimeEnvironment->expects($this->once())->method('DoCompile') + ->willThrowException(new \CoreException('SHADOK MSG')); + $oSequencer = new DataAuditSequencer($this->GivenParams(), $oRunTimeEnvironment); + + $aRes = $oSequencer->ExecuteStep('compile'); + $aExpected = [ + 'status' => 2, + 'message' => 'SHADOK MSG', + 'next-step' => '', + 'next-step-label' => '', + 'prev-step-success-message' => '', + 'percentage-completed' => 100, + 'error_code' => 0, + ]; + $this->assertEquals($aExpected, $aRes); + } + + public function testAuditCalled() + { + $oRunTimeEnvironment = $this->createMock(\RunTimeEnvironment::class); + $oRunTimeEnvironment->expects($this->once())->method('GetApplicationVersion') + ->willReturn(['product_version' => ITOP_VERSION_FULL]); + $oRunTimeEnvironment->expects($this->once())->method('DataToCleanupAudit'); + $oRunTimeEnvironment->expects($this->any())->method('GetFinalEnv') + ->willReturn('production'); + + $aAdditionalParams = [ + 'mode' => 'update', + 'optional_steps' => ['setup-audit' => true ], + ]; + $oSequencer = new DataAuditSequencer($this->GivenParams($aAdditionalParams), $oRunTimeEnvironment); + + $aRes = $oSequencer->ExecuteStep('setup-audit'); + $aExpected = [ + 'status' => 1, + 'message' => '', + 'next-step' => 'complete', + 'next-step-label' => 'Check Completed', + 'prev-step-success-message' => 'Data consistency check completed', + 'percentage-completed' => 75, + ]; + $this->assertEquals($aExpected, $aRes); + } + + public function testNoAuditInUpgradeModeWhenNoRuntimeEnvironmentAvailable() + { + $oRunTimeEnvironment = $this->createMock(\RunTimeEnvironment::class); + $oRunTimeEnvironment->expects($this->once())->method('GetApplicationVersion') + ->willReturn(['product_version' => ITOP_VERSION_FULL]); + $oRunTimeEnvironment->expects($this->never())->method('DataToCleanupAudit'); + $oRunTimeEnvironment->expects($this->once())->method('GetFinalEnv') + ->willReturn('gabuzomeu'); + + $aAdditionalParams = [ + 'mode' => 'update', + 'optional_steps' => ['copy' => true, 'setup-audit' => true ], + ]; + $oSequencer = new DataAuditSequencer($this->GivenParams($aAdditionalParams), $oRunTimeEnvironment); + + $expected = [ + '', + 'copy', + 'compile', + 'complete', + ]; + $this->assertEquals($expected, $oSequencer->GetStepNames()); + } + + public function testNoAuditInFreshInstallMode() + { + $oRunTimeEnvironment = $this->createMock(\RunTimeEnvironment::class); + $oRunTimeEnvironment->expects($this->never())->method('GetFinalEnv'); + $oRunTimeEnvironment->expects($this->never())->method('DataToCleanupAudit'); + $aAdditionalParams = [ + 'mode' => 'install', + 'optional_steps' => ['copy' => true, 'setup-audit' => true ], + ]; + $oSequencer = new DataAuditSequencer($this->GivenParams($aAdditionalParams), $oRunTimeEnvironment); + + $expected = [ + '', + 'copy', + 'compile', + 'complete', + ]; + $this->assertEquals($expected, $oSequencer->GetStepNames()); + } + + public function testGetStepNamesForAllSteps() + { + $oRunTimeEnvironment = $this->createMock(\RunTimeEnvironment::class); + $oRunTimeEnvironment->expects($this->once())->method('GetApplicationVersion') + ->willReturn(['product_version' => ITOP_VERSION_FULL]); + $oRunTimeEnvironment->expects($this->any())->method('GetFinalEnv') + ->willReturn('production'); + $aAdditionalParams = [ + 'mode' => 'update', + 'optional_steps' => ['copy' => true, 'setup-audit' => true ], + ]; + $oSequencer = new DataAuditSequencer($this->GivenParams($aAdditionalParams), $oRunTimeEnvironment); + + $expected = [ + '', + 'copy', + 'compile', + 'setup-audit', + 'complete', + ]; + $this->assertEquals($expected, $oSequencer->GetStepNames()); + } + + private function GivenParams(array $aAdditionalParams = []): PHPParameters + { + $oParams = new PHPParameters(); + $aParams = array_merge([ + 'mode' => 'install', + 'optional_steps' => [ + 'copy' => true, + ], + 'database' => [ + 'server' => 'server', + 'user' => 'user', + 'pwd' => 'pwd', + 'name' => 'name', + 'prefix' => 'prefix', + 'db_tls_enabled' => 'db_tls_enabled', + 'db_tls_ca' => 'db_tls_ca', + ], + 'application_path' => '', + 'language' => '', + 'graphviz_path' => '', + 'source_dir' => '', + ], $aAdditionalParams); + + $oParams->LoadFromHash($aParams); + return $oParams; + } + + public function testIsDataAuditRequired_NoAuditInFreshInstall() + { + $this->oConfig = $this->createMock(\Config::class); + + $oRunTimeEnvironment = $this->createMock(\RunTimeEnvironment::class); + $oRunTimeEnvironment->expects($this->once())->method("GetBuildEnv")->willReturn("production-test"); + + $oSequencer = new DataAuditSequencer($this->GivenParams(), $oRunTimeEnvironment); + $this->SetNonPublicProperty($oSequencer, 'oTestConfig', $this->oConfig); + self::assertFalse($this->InvokeNonPublicMethod(DataAuditSequencer::class, "IsDataAuditRequired", $oSequencer)); + } + + public function testIsDataAuditRequired_NoAuditOnPackageUpgrade() + { + $oRunTimeEnvironment = $this->createMock(\RunTimeEnvironment::class); + $oRunTimeEnvironment->expects($this->once())->method('GetApplicationVersion') + ->willReturn(['product_version' => ITOP_VERSION_FULL."_alpha"]); + $oRunTimeEnvironment->expects($this->never())->method("GetFinalEnv"); + + $aAdditionalParams = [ + 'mode' => 'upgrade', + 'optional_steps' => ['setup-audit' => true ], + ]; + $oSequencer = new DataAuditSequencer($this->GivenParams($aAdditionalParams), $oRunTimeEnvironment); + self::assertFalse($this->InvokeNonPublicMethod(DataAuditSequencer::class, "IsDataAuditRequired", $oSequencer)); + } + + public function testIsDataAuditRequired_NoAuditOnSystemChange() + { + $oRunTimeEnvironment = $this->createMock(\RunTimeEnvironment::class); + $oRunTimeEnvironment->expects($this->once())->method('GetApplicationVersion') + ->willReturn(['product_version' => ITOP_VERSION_FULL]); + $oRunTimeEnvironment->expects($this->once())->method("GetFinalEnv")->willReturn("production-gabuzomeu"); + + $aAdditionalParams = [ + 'mode' => 'upgrade', + 'optional_steps' => ['setup-audit' => true ], + ]; + $oSequencer = new DataAuditSequencer($this->GivenParams($aAdditionalParams), $oRunTimeEnvironment); + self::assertFalse($this->InvokeNonPublicMethod(DataAuditSequencer::class, "IsDataAuditRequired", $oSequencer)); + } + + public function testIsDataAuditRequired_NoAuditTriggeredBecauseDisabled() + { + $oRunTimeEnvironment = $this->createMock(\RunTimeEnvironment::class); + $oRunTimeEnvironment->expects($this->never())->method('GetApplicationVersion') + ->willReturn(['product_version' => ITOP_VERSION_FULL]); + $oRunTimeEnvironment->expects($this->never())->method("GetFinalEnv")->willReturn("production"); + + $aAdditionalParams = [ + 'mode' => 'upgrade', + ]; + $oSequencer = new DataAuditSequencer($this->GivenParams($aAdditionalParams), $oRunTimeEnvironment); + self::assertFalse($this->InvokeNonPublicMethod(DataAuditSequencer::class, "IsDataAuditRequired", $oSequencer)); + } + + public function testIsDataAuditRequired_AuditTriggered() + { + $oRunTimeEnvironment = $this->createMock(\RunTimeEnvironment::class); + $oRunTimeEnvironment->expects($this->once())->method('GetApplicationVersion') + ->willReturn(['product_version' => ITOP_VERSION_FULL]); + $oRunTimeEnvironment->expects($this->once())->method("GetFinalEnv")->willReturn("production"); + + $aAdditionalParams = [ + 'mode' => 'upgrade', + 'optional_steps' => ['setup-audit' => true ], + ]; + $oSequencer = new DataAuditSequencer($this->GivenParams($aAdditionalParams), $oRunTimeEnvironment); + self::assertTrue($this->InvokeNonPublicMethod(DataAuditSequencer::class, "IsDataAuditRequired", $oSequencer)); + } +} diff --git a/tests/php-unit-tests/unitary-tests/setup/unattended-install/resources/AnalyzeInstallation.json b/tests/php-unit-tests/unitary-tests/setup/unattended-install/resources/AnalyzeInstallation.json index 7000b45d82..916272d810 100644 --- a/tests/php-unit-tests/unitary-tests/setup/unattended-install/resources/AnalyzeInstallation.json +++ b/tests/php-unit-tests/unitary-tests/setup/unattended-install/resources/AnalyzeInstallation.json @@ -1 +1 @@ -{"_Root_":{"version_db":"","name_db":"","version_code":"2.7.0-dev-svn","name_code":"iTop"},"authent-cas":{"label":"CAS SSO","category":"authentication","dependencies":[],"mandatory":true,"visible":true,"datamodel":["model.authent-cas.php","vendor\/autoload.php","src\/CASLoginExtension.php"],"webservice":[],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":{"cas_debug":false,"cas_host":"","cas_port":"","cas_context":"","cas_version":"","service_base_url":""},"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/authent-cas","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/authent-cas\/module.authent-cas.php","dictionary":["2.x\/authent-cas\/de.dict.authent-cas.php","2.x\/authent-cas\/cs.dict.authent-cas.php","2.x\/authent-cas\/nl.dict.authent-cas.php","2.x\/authent-cas\/da.dict.authent-cas.php","2.x\/authent-cas\/tr.dict.authent-cas.php","2.x\/authent-cas\/ru.dict.authent-cas.php","2.x\/authent-cas\/ja.dict.authent-cas.php","2.x\/authent-cas\/es_cr.dict.authent-cas.php","2.x\/authent-cas\/it.dict.authent-cas.php","2.x\/authent-cas\/pt_br.dict.authent-cas.php","2.x\/authent-cas\/sk.dict.authent-cas.php","2.x\/authent-cas\/hu.dict.authent-cas.php","2.x\/authent-cas\/zh_cn.dict.authent-cas.php","2.x\/authent-cas\/en.dict.authent-cas.php","2.x\/authent-cas\/fr.dict.authent-cas.php"],"version_db":"","version_code":"2.7.10","install":{"flag":2,"message":"the module is part of the application"}},"authent-external":{"label":"External user authentication","category":"authentication","dependencies":[],"mandatory":false,"visible":true,"datamodel":["model.authent-external.php"],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/authent-external","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/authent-external\/module.authent-external.php","dictionary":["2.x\/authent-external\/fr.dict.authent-external.php","2.x\/authent-external\/de.dict.authent-external.php","2.x\/authent-external\/zh_cn.dict.authent-external.php","2.x\/authent-external\/tr.dict.authent-external.php","2.x\/authent-external\/pt_br.dict.authent-external.php","2.x\/authent-external\/da.dict.authent-external.php","2.x\/authent-external\/ru.dict.authent-external.php","2.x\/authent-external\/cs.dict.authent-external.php","2.x\/authent-external\/it.dict.authent-external.php","2.x\/authent-external\/en.dict.authent-external.php","2.x\/authent-external\/hu.dict.authent-external.php","2.x\/authent-external\/sk.dict.authent-external.php","2.x\/authent-external\/ja.dict.authent-external.php","2.x\/authent-external\/nl.dict.authent-external.php","2.x\/authent-external\/es_cr.dict.authent-external.php"],"version_db":"","version_code":"2.7.10","install":{"flag":1,"message":""}},"authent-ldap":{"label":"User authentication based on LDAP","category":"authentication","dependencies":[],"mandatory":false,"visible":true,"datamodel":["model.authent-ldap.php"],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":{"host":"localhost","port":389,"default_user":"","default_pwd":"","base_dn":"dc=yourcompany,dc=com","user_query":"(&(uid=%1$s)(inetuserstatus=ACTIVE))","options":{"17":3,"8":0},"start_tls":false,"debug":false},"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/authent-ldap","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/authent-ldap\/module.authent-ldap.php","dictionary":["2.x\/authent-ldap\/en.dict.authent-ldap.php","2.x\/authent-ldap\/ru.dict.authent-ldap.php","2.x\/authent-ldap\/cs.dict.authent-ldap.php","2.x\/authent-ldap\/es_cr.dict.authent-ldap.php","2.x\/authent-ldap\/zh_cn.dict.authent-ldap.php","2.x\/authent-ldap\/pt_br.dict.authent-ldap.php","2.x\/authent-ldap\/it.dict.authent-ldap.php","2.x\/authent-ldap\/tr.dict.authent-ldap.php","2.x\/authent-ldap\/fr.dict.authent-ldap.php","2.x\/authent-ldap\/de.dict.authent-ldap.php","2.x\/authent-ldap\/da.dict.authent-ldap.php","2.x\/authent-ldap\/nl.dict.authent-ldap.php","2.x\/authent-ldap\/hu.dict.authent-ldap.php","2.x\/authent-ldap\/sk.dict.authent-ldap.php","2.x\/authent-ldap\/ja.dict.authent-ldap.php"],"version_db":"","version_code":"2.7.10","install":{"flag":1,"message":""}},"authent-local":{"label":"User authentication based on the local DB","category":"authentication","dependencies":[],"mandatory":true,"visible":true,"datamodel":["model.authent-local.php"],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/authent-local","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/authent-local\/module.authent-local.php","dictionary":["2.x\/authent-local\/hu.dict.authent-local.php","2.x\/authent-local\/de.dict.authent-local.php","2.x\/authent-local\/ja.dict.authent-local.php","2.x\/authent-local\/fr.dict.authent-local.php","2.x\/authent-local\/es_cr.dict.authent-local.php","2.x\/authent-local\/it.dict.authent-local.php","2.x\/authent-local\/tr.dict.authent-local.php","2.x\/authent-local\/da.dict.authent-local.php","2.x\/authent-local\/sk.dict.authent-local.php","2.x\/authent-local\/ru.dict.authent-local.php","2.x\/authent-local\/nl.dict.authent-local.php","2.x\/authent-local\/zh_cn.dict.authent-local.php","2.x\/authent-local\/cs.dict.authent-local.php","2.x\/authent-local\/en.dict.authent-local.php","2.x\/authent-local\/pt_br.dict.authent-local.php"],"version_db":"","version_code":"2.7.10","install":{"flag":2,"message":"the module is part of the application"}},"combodo-db-tools":{"label":"Database maintenance tools","category":"business","dependencies":[],"mandatory":false,"visible":true,"datamodel":["model.combodo-db-tools.php","src\/Service\/DBToolsUtils.php","src\/Service\/DBAnalyzerUtils.php"],"webservice":[],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/combodo-db-tools","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/combodo-db-tools\/module.combodo-db-tools.php","dictionary":["2.x\/combodo-db-tools\/en.dict.combodo-db-tools.php","2.x\/combodo-db-tools\/pt_br.dict.combodo-db-tools.php","2.x\/combodo-db-tools\/zh_cn.dict.combodo-db-tools.php","2.x\/combodo-db-tools\/nl.dict.combodo-db-tools.php","2.x\/combodo-db-tools\/ru.dict.combodo-db-tools.php","2.x\/combodo-db-tools\/es_cr.dict.combodo-db-tools.php","2.x\/combodo-db-tools\/tr.dict.combodo-db-tools.php","2.x\/combodo-db-tools\/da.dict.combodo-db-tools.php","2.x\/combodo-db-tools\/ja.dict.combodo-db-tools.php","2.x\/combodo-db-tools\/de.dict.combodo-db-tools.php","2.x\/combodo-db-tools\/hu.dict.combodo-db-tools.php","2.x\/combodo-db-tools\/fr.dict.combodo-db-tools.php","2.x\/combodo-db-tools\/it.dict.combodo-db-tools.php","2.x\/combodo-db-tools\/sk.dict.combodo-db-tools.php","2.x\/combodo-db-tools\/cs.dict.combodo-db-tools.php"],"version_db":"","version_code":"2.7.10","install":{"flag":1,"message":""}},"combodo-monitoring":{"label":"Combodo Monitoring","category":"monitoring","dependencies":[],"mandatory":false,"visible":true,"datamodel":["vendor\/autoload.php"],"webservice":[],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"\/var\/www\/html\/iTop\/extensions\/combodo-monitoring","module_file":"\/var\/www\/html\/iTop\/extensions\/combodo-monitoring\/module.combodo-monitoring.php","version_db":"","version_code":"1.0.7","install":{"flag":1,"message":""}},"itop-attachments":{"label":"Tickets Attachments","category":"business","dependencies":[],"mandatory":false,"visible":true,"installer":"AttachmentInstaller","datamodel":["model.itop-attachments.php","main.itop-attachments.php","renderers.itop-attachments.php"],"webservice":[],"dictionary":["2.x\/itop-attachments\/cs.dict.itop-attachments.php","2.x\/itop-attachments\/ja.dict.itop-attachments.php","2.x\/itop-attachments\/es_cr.dict.itop-attachments.php","2.x\/itop-attachments\/ru.dict.itop-attachments.php","2.x\/itop-attachments\/it.dict.itop-attachments.php","2.x\/itop-attachments\/zh_cn.dict.itop-attachments.php","2.x\/itop-attachments\/hu.dict.itop-attachments.php","2.x\/itop-attachments\/da.dict.itop-attachments.php","2.x\/itop-attachments\/en.dict.itop-attachments.php","2.x\/itop-attachments\/sk.dict.itop-attachments.php","2.x\/itop-attachments\/pt_br.dict.itop-attachments.php","2.x\/itop-attachments\/fr.dict.itop-attachments.php","2.x\/itop-attachments\/de.dict.itop-attachments.php","2.x\/itop-attachments\/tr.dict.itop-attachments.php","2.x\/itop-attachments\/nl.dict.itop-attachments.php"],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":{"allowed_classes":["Ticket"],"position":"relations","preview_max_width":290},"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-attachments","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-attachments\/module.itop-attachments.php","version_db":"","version_code":"2.7.10","install":{"flag":1,"message":""}},"itop-backup":{"label":"Backup utilities","category":"Application management","dependencies":[],"mandatory":true,"visible":false,"datamodel":["main.itop-backup.php","model.itop-backup.php"],"webservice":[],"dictionary":["en.dict.itop-backup.php","fr.dict.itop-backup.php","2.x\/itop-backup\/cs.dict.itop-backup.php","2.x\/itop-backup\/es_cr.dict.itop-backup.php","2.x\/itop-backup\/fr.dict.itop-backup.php","2.x\/itop-backup\/de.dict.itop-backup.php","2.x\/itop-backup\/ja.dict.itop-backup.php","2.x\/itop-backup\/en.dict.itop-backup.php","2.x\/itop-backup\/hu.dict.itop-backup.php","2.x\/itop-backup\/nl.dict.itop-backup.php","2.x\/itop-backup\/it.dict.itop-backup.php","2.x\/itop-backup\/sk.dict.itop-backup.php","2.x\/itop-backup\/ru.dict.itop-backup.php","2.x\/itop-backup\/tr.dict.itop-backup.php","2.x\/itop-backup\/pt_br.dict.itop-backup.php","2.x\/itop-backup\/da.dict.itop-backup.php","2.x\/itop-backup\/zh_cn.dict.itop-backup.php"],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":{"mysql_bindir":"","week_days":"monday, tuesday, wednesday, thursday, friday","time":"23:30","retention_count":5,"enabled":true,"itop_backup_incident":""},"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-backup","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-backup\/module.itop-backup.php","version_db":"","version_code":"2.7.10","install":{"flag":2,"message":"the module is part of the application"}},"itop-config-mgmt":{"label":"Configuration Management (CMDB)","category":"business","dependencies":[],"mandatory":true,"visible":true,"installer":"ConfigMgmtInstaller","datamodel":["model.itop-config-mgmt.php","main.itop-config-mgmt.php"],"data.struct":[],"data.sample":["data.sample.organizations.xml","data.sample.brand.xml","data.sample.model.xml","data.sample.osfamily.xml","data.sample.osversion.xml","data.sample.networkdevicetype.xml","data.sample.contacttype.xml","data.sample.locations.xml","data.sample.persons.xml","data.sample.teams.xml","data.sample.contactteam.xml","data.sample.servers.xml","data.sample.nw-devices.xml","data.sample.software.xml","data.sample.dbserver.xml","data.sample.dbschema.xml","data.sample.webserver.xml","data.sample.webapp.xml","data.sample.applications.xml","data.sample.applicationsolutionci.xml"],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-config-mgmt","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-config-mgmt\/module.itop-config-mgmt.php","dictionary":["2.x\/itop-config-mgmt\/ru.dict.itop-config-mgmt.php","2.x\/itop-config-mgmt\/tr.dict.itop-config-mgmt.php","2.x\/itop-config-mgmt\/it.dict.itop-config-mgmt.php","2.x\/itop-config-mgmt\/de.dict.itop-config-mgmt.php","2.x\/itop-config-mgmt\/fr.dict.itop-config-mgmt.php","2.x\/itop-config-mgmt\/hu.dict.itop-config-mgmt.php","2.x\/itop-config-mgmt\/nl.dict.itop-config-mgmt.php","2.x\/itop-config-mgmt\/en.dict.itop-config-mgmt.php","2.x\/itop-config-mgmt\/cs.dict.itop-config-mgmt.php","2.x\/itop-config-mgmt\/ja.dict.itop-config-mgmt.php","2.x\/itop-config-mgmt\/sk.dict.itop-config-mgmt.php","2.x\/itop-config-mgmt\/zh_cn.dict.itop-config-mgmt.php","2.x\/itop-config-mgmt\/da.dict.itop-config-mgmt.php","2.x\/itop-config-mgmt\/pt_br.dict.itop-config-mgmt.php","2.x\/itop-config-mgmt\/es_cr.dict.itop-config-mgmt.php"],"version_db":"","version_code":"2.7.10","install":{"flag":2,"message":"the module is part of the application"}},"itop-config":{"label":"Configuration editor","category":"Application management","dependencies":[],"mandatory":true,"visible":false,"datamodel":["model.itop-config.php","src\/Validator\/ConfigNodesVisitor.php","src\/Validator\/iTopConfigAstValidator.php","src\/Validator\/iTopConfigSyntaxValidator.php"],"webservice":[],"dictionary":["en.dict.itop-config.php","fr.dict.itop-config.php","2.x\/itop-config\/ru.dict.itop-config.php","2.x\/itop-config\/en.dict.itop-config.php","2.x\/itop-config\/sk.dict.itop-config.php","2.x\/itop-config\/cs.dict.itop-config.php","2.x\/itop-config\/de.dict.itop-config.php","2.x\/itop-config\/zh_cn.dict.itop-config.php","2.x\/itop-config\/nl.dict.itop-config.php","2.x\/itop-config\/es_cr.dict.itop-config.php","2.x\/itop-config\/da.dict.itop-config.php","2.x\/itop-config\/ja.dict.itop-config.php","2.x\/itop-config\/pt_br.dict.itop-config.php","2.x\/itop-config\/tr.dict.itop-config.php","2.x\/itop-config\/hu.dict.itop-config.php","2.x\/itop-config\/it.dict.itop-config.php","2.x\/itop-config\/fr.dict.itop-config.php"],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-config","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-config\/module.itop-config.php","version_db":"","version_code":"2.7.10","install":{"flag":2,"message":"the module is part of the application"}},"itop-datacenter-mgmt":{"label":"Datacenter Management","category":"business","dependencies":["itop-config-mgmt\/2.2.0"],"mandatory":false,"visible":true,"datamodel":["model.itop-datacenter-mgmt.php"],"webservice":[],"data.struct":[],"data.sample":["data.sample.racks.xml"],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-datacenter-mgmt","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-datacenter-mgmt\/module.itop-datacenter-mgmt.php","dictionary":["2.x\/itop-datacenter-mgmt\/tr.dict.itop-datacenter-mgmt.php","2.x\/itop-datacenter-mgmt\/ja.dict.itop-datacenter-mgmt.php","2.x\/itop-datacenter-mgmt\/sk.dict.itop-datacenter-mgmt.php","2.x\/itop-datacenter-mgmt\/da.dict.itop-datacenter-mgmt.php","2.x\/itop-datacenter-mgmt\/es_cr.dict.itop-datacenter-mgmt.php","2.x\/itop-datacenter-mgmt\/ru.dict.itop-datacenter-mgmt.php","2.x\/itop-datacenter-mgmt\/en.dict.itop-datacenter-mgmt.php","2.x\/itop-datacenter-mgmt\/it.dict.itop-datacenter-mgmt.php","2.x\/itop-datacenter-mgmt\/zh_cn.dict.itop-datacenter-mgmt.php","2.x\/itop-datacenter-mgmt\/de.dict.itop-datacenter-mgmt.php","2.x\/itop-datacenter-mgmt\/hu.dict.itop-datacenter-mgmt.php","2.x\/itop-datacenter-mgmt\/cs.dict.itop-datacenter-mgmt.php","2.x\/itop-datacenter-mgmt\/fr.dict.itop-datacenter-mgmt.php","2.x\/itop-datacenter-mgmt\/pt_br.dict.itop-datacenter-mgmt.php","2.x\/itop-datacenter-mgmt\/nl.dict.itop-datacenter-mgmt.php"],"version_db":"","version_code":"2.7.10","install":{"flag":1,"message":""}},"itop-endusers-devices":{"label":"End-user Devices Management","category":"business","dependencies":["itop-config-mgmt\/2.2.0"],"mandatory":false,"visible":true,"installer":"EndUserMgmtInstaller","datamodel":["model.itop-endusers-devices.php"],"webservice":[],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-endusers-devices","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-endusers-devices\/module.itop-endusers-devices.php","dictionary":["2.x\/itop-endusers-devices\/cs.dict.itop-endusers-devices.php","2.x\/itop-endusers-devices\/en.dict.itop-endusers-devices.php","2.x\/itop-endusers-devices\/ru.dict.itop-endusers-devices.php","2.x\/itop-endusers-devices\/it.dict.itop-endusers-devices.php","2.x\/itop-endusers-devices\/sk.dict.itop-endusers-devices.php","2.x\/itop-endusers-devices\/es_cr.dict.itop-endusers-devices.php","2.x\/itop-endusers-devices\/de.dict.itop-endusers-devices.php","2.x\/itop-endusers-devices\/fr.dict.itop-endusers-devices.php","2.x\/itop-endusers-devices\/tr.dict.itop-endusers-devices.php","2.x\/itop-endusers-devices\/hu.dict.itop-endusers-devices.php","2.x\/itop-endusers-devices\/da.dict.itop-endusers-devices.php","2.x\/itop-endusers-devices\/zh_cn.dict.itop-endusers-devices.php","2.x\/itop-endusers-devices\/nl.dict.itop-endusers-devices.php","2.x\/itop-endusers-devices\/ja.dict.itop-endusers-devices.php","2.x\/itop-endusers-devices\/pt_br.dict.itop-endusers-devices.php"],"version_db":"","version_code":"2.7.10","install":{"flag":1,"message":""}},"itop-files-information":{"label":"iTop files information","category":"business","dependencies":[],"mandatory":false,"visible":false,"datamodel":["model.itop-files-information.php","src\/Service\/FilesInformation.php","src\/Service\/FilesInformationException.php","src\/Service\/FilesInformationUtils.php","src\/Service\/FilesIntegrity.php"],"webservice":[],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-files-information","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-files-information\/module.itop-files-information.php","dictionary":["2.x\/itop-files-information\/sk.dict.itop-files-information.php","2.x\/itop-files-information\/cs.dict.itop-files-information.php","2.x\/itop-files-information\/ja.dict.itop-files-information.php","2.x\/itop-files-information\/hu.dict.itop-files-information.php","2.x\/itop-files-information\/fr.dict.itop-files-information.php","2.x\/itop-files-information\/pt_br.dict.itop-files-information.php","2.x\/itop-files-information\/es_cr.dict.itop-files-information.php","2.x\/itop-files-information\/tr.dict.itop-files-information.php","2.x\/itop-files-information\/zh_cn.dict.itop-files-information.php","2.x\/itop-files-information\/en.dict.itop-files-information.php","2.x\/itop-files-information\/da.dict.itop-files-information.php","2.x\/itop-files-information\/de.dict.itop-files-information.php","2.x\/itop-files-information\/nl.dict.itop-files-information.php","2.x\/itop-files-information\/it.dict.itop-files-information.php","2.x\/itop-files-information\/ru.dict.itop-files-information.php"],"version_db":"","version_code":"2.7.10","install":{"flag":1,"message":""}},"itop-hub-connector":{"label":"iTop Hub Connector","category":"business","dependencies":["itop-config-mgmt\/2.4.0"],"mandatory":false,"visible":true,"datamodel":["menus.php","hubnewsroomprovider.class.inc.php","model.itop-hub-connector.php"],"webservice":[],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-hub-connector","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-hub-connector\/module.itop-hub-connector.php","dictionary":["2.x\/itop-hub-connector\/it.dict.itop-hub-connector.php","2.x\/itop-hub-connector\/zh_cn.dict.itop-hub-connector.php","2.x\/itop-hub-connector\/sk.dict.itop-hub-connector.php","2.x\/itop-hub-connector\/cs.dict.itop-hub-connector.php","2.x\/itop-hub-connector\/fr.dict.itop-hub-connector.php","2.x\/itop-hub-connector\/hu.dict.itop-hub-connector.php","2.x\/itop-hub-connector\/ru.dict.itop-hub-connector.php","2.x\/itop-hub-connector\/ja.dict.itop-hub-connector.php","2.x\/itop-hub-connector\/en.dict.itop-hub-connector.php","2.x\/itop-hub-connector\/es_cr.dict.itop-hub-connector.php","2.x\/itop-hub-connector\/tr.dict.itop-hub-connector.php","2.x\/itop-hub-connector\/nl.dict.itop-hub-connector.php","2.x\/itop-hub-connector\/de.dict.itop-hub-connector.php","2.x\/itop-hub-connector\/pt_br.dict.itop-hub-connector.php","2.x\/itop-hub-connector\/da.dict.itop-hub-connector.php"],"version_db":"","version_code":"2.7.10","install":{"flag":1,"message":""}},"itop-portal-base":{"label":"Portal Development Library","category":"Portal","dependencies":[],"mandatory":true,"visible":false,"datamodel":["portal\/vendor\/autoload.php","model.itop-portal-base.php"],"webservice":[],"dictionary":["2.x\/itop-portal-base\/hu.dict.itop-portal-base.php","2.x\/itop-portal-base\/ja.dict.itop-portal-base.php","2.x\/itop-portal-base\/cs.dict.itop-portal-base.php","2.x\/itop-portal-base\/zh_cn.dict.itop-portal-base.php","2.x\/itop-portal-base\/tr.dict.itop-portal-base.php","2.x\/itop-portal-base\/pt_br.dict.itop-portal-base.php","2.x\/itop-portal-base\/nl.dict.itop-portal-base.php","2.x\/itop-portal-base\/it.dict.itop-portal-base.php","2.x\/itop-portal-base\/es_cr.dict.itop-portal-base.php","2.x\/itop-portal-base\/fr.dict.itop-portal-base.php","2.x\/itop-portal-base\/ru.dict.itop-portal-base.php","2.x\/itop-portal-base\/de.dict.itop-portal-base.php","2.x\/itop-portal-base\/da.dict.itop-portal-base.php","2.x\/itop-portal-base\/en.dict.itop-portal-base.php","2.x\/itop-portal-base\/sk.dict.itop-portal-base.php"],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-portal-base","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-portal-base\/module.itop-portal-base.php","version_db":"","version_code":"2.7.10","install":{"flag":2,"message":"the module is part of the application"}},"itop-portal":{"label":"Enhanced Customer Portal","category":"Portal","dependencies":["itop-portal-base\/2.7.0"],"mandatory":false,"visible":true,"datamodel":["main.itop-portal.php","model.itop-portal.php"],"webservice":[],"dictionary":[],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-portal","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-portal\/module.itop-portal.php","version_db":"","version_code":"2.7.10","install":{"flag":1,"message":""}},"itop-profiles-itil":{"label":"Create standard ITIL profiles","category":"create_profiles","dependencies":[],"mandatory":true,"visible":false,"datamodel":["model.itop-profiles-itil.php"],"webservice":[],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-profiles-itil","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-profiles-itil\/module.itop-profiles-itil.php","version_db":"","version_code":"2.7.10","install":{"flag":2,"message":"the module is part of the application"}},"itop-sla-computation":{"label":"SLA Computation","category":"sla","dependencies":[],"mandatory":true,"visible":false,"datamodel":["main.itop-sla-computation.php"],"webservice":[],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-sla-computation","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-sla-computation\/module.itop-sla-computation.php","dictionary":["2.x\/itop-sla-computation\/de.dict.itop-sla-computation.php","2.x\/itop-sla-computation\/it.dict.itop-sla-computation.php","2.x\/itop-sla-computation\/tr.dict.itop-sla-computation.php","2.x\/itop-sla-computation\/nl.dict.itop-sla-computation.php","2.x\/itop-sla-computation\/zh_cn.dict.itop-sla-computation.php","2.x\/itop-sla-computation\/hu.dict.itop-sla-computation.php","2.x\/itop-sla-computation\/ja.dict.itop-sla-computation.php","2.x\/itop-sla-computation\/pt_br.dict.itop-sla-computation.php","2.x\/itop-sla-computation\/es_cr.dict.itop-sla-computation.php","2.x\/itop-sla-computation\/fr.dict.itop-sla-computation.php","2.x\/itop-sla-computation\/cs.dict.itop-sla-computation.php","2.x\/itop-sla-computation\/sk.dict.itop-sla-computation.php","2.x\/itop-sla-computation\/da.dict.itop-sla-computation.php","2.x\/itop-sla-computation\/en.dict.itop-sla-computation.php","2.x\/itop-sla-computation\/ru.dict.itop-sla-computation.php"],"version_db":"","version_code":"2.7.10","install":{"flag":2,"message":"the module is part of the application"}},"itop-storage-mgmt":{"label":"Advanced Storage Management","category":"business","dependencies":["itop-config-mgmt\/2.4.0"],"mandatory":false,"visible":true,"installer":"StorageMgmtInstaller","datamodel":["model.itop-storage-mgmt.php"],"webservice":[],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-storage-mgmt","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-storage-mgmt\/module.itop-storage-mgmt.php","dictionary":["2.x\/itop-storage-mgmt\/en.dict.itop-storage-mgmt.php","2.x\/itop-storage-mgmt\/cs.dict.itop-storage-mgmt.php","2.x\/itop-storage-mgmt\/ja.dict.itop-storage-mgmt.php","2.x\/itop-storage-mgmt\/da.dict.itop-storage-mgmt.php","2.x\/itop-storage-mgmt\/pt_br.dict.itop-storage-mgmt.php","2.x\/itop-storage-mgmt\/it.dict.itop-storage-mgmt.php","2.x\/itop-storage-mgmt\/nl.dict.itop-storage-mgmt.php","2.x\/itop-storage-mgmt\/fr.dict.itop-storage-mgmt.php","2.x\/itop-storage-mgmt\/tr.dict.itop-storage-mgmt.php","2.x\/itop-storage-mgmt\/es_cr.dict.itop-storage-mgmt.php","2.x\/itop-storage-mgmt\/sk.dict.itop-storage-mgmt.php","2.x\/itop-storage-mgmt\/zh_cn.dict.itop-storage-mgmt.php","2.x\/itop-storage-mgmt\/de.dict.itop-storage-mgmt.php","2.x\/itop-storage-mgmt\/hu.dict.itop-storage-mgmt.php","2.x\/itop-storage-mgmt\/ru.dict.itop-storage-mgmt.php"],"version_db":"","version_code":"2.7.10","install":{"flag":1,"message":""}},"itop-tickets":{"label":"Tickets Management","category":"business","dependencies":["itop-config-mgmt\/2.4.0"],"mandatory":true,"visible":false,"installer":"TicketsInstaller","datamodel":["main.itop-tickets.php","model.itop-tickets.php"],"data.struct":[],"data.sample":[],"doc.manual_setup":"\/documentation\/itop-tickets.htm","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-tickets","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-tickets\/module.itop-tickets.php","dictionary":["2.x\/itop-tickets\/cs.dict.itop-tickets.php","2.x\/itop-tickets\/da.dict.itop-tickets.php","2.x\/itop-tickets\/es_cr.dict.itop-tickets.php","2.x\/itop-tickets\/tr.dict.itop-tickets.php","2.x\/itop-tickets\/nl.dict.itop-tickets.php","2.x\/itop-tickets\/it.dict.itop-tickets.php","2.x\/itop-tickets\/en.dict.itop-tickets.php","2.x\/itop-tickets\/pt_br.dict.itop-tickets.php","2.x\/itop-tickets\/fr.dict.itop-tickets.php","2.x\/itop-tickets\/sk.dict.itop-tickets.php","2.x\/itop-tickets\/ja.dict.itop-tickets.php","2.x\/itop-tickets\/ru.dict.itop-tickets.php","2.x\/itop-tickets\/hu.dict.itop-tickets.php","2.x\/itop-tickets\/de.dict.itop-tickets.php","2.x\/itop-tickets\/zh_cn.dict.itop-tickets.php"],"version_db":"","version_code":"2.7.10","install":{"flag":2,"message":"the module is part of the application"}},"itop-virtualization-mgmt":{"label":"Virtualization Management","category":"business","dependencies":["itop-config-mgmt\/2.4.0"],"mandatory":false,"visible":true,"datamodel":["model.itop-virtualization-mgmt.php"],"webservice":[],"data.struct":[],"data.sample":["data.sample.farm.xml","data.sample.hypervisor.xml","data.sample.vm.xml","data.sample.dbserver.xml","data.sample.dbschema.xml","data.sample.webserver.xml","data.sample.webapp.xml","data.sample.applicationsolutionci.xml"],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-virtualization-mgmt","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-virtualization-mgmt\/module.itop-virtualization-mgmt.php","dictionary":["2.x\/itop-virtualization-mgmt\/de.dict.itop-virtualization-mgmt.php","2.x\/itop-virtualization-mgmt\/nl.dict.itop-virtualization-mgmt.php","2.x\/itop-virtualization-mgmt\/ja.dict.itop-virtualization-mgmt.php","2.x\/itop-virtualization-mgmt\/zh_cn.dict.itop-virtualization-mgmt.php","2.x\/itop-virtualization-mgmt\/ru.dict.itop-virtualization-mgmt.php","2.x\/itop-virtualization-mgmt\/sk.dict.itop-virtualization-mgmt.php","2.x\/itop-virtualization-mgmt\/tr.dict.itop-virtualization-mgmt.php","2.x\/itop-virtualization-mgmt\/fr.dict.itop-virtualization-mgmt.php","2.x\/itop-virtualization-mgmt\/cs.dict.itop-virtualization-mgmt.php","2.x\/itop-virtualization-mgmt\/da.dict.itop-virtualization-mgmt.php","2.x\/itop-virtualization-mgmt\/hu.dict.itop-virtualization-mgmt.php","2.x\/itop-virtualization-mgmt\/es_cr.dict.itop-virtualization-mgmt.php","2.x\/itop-virtualization-mgmt\/en.dict.itop-virtualization-mgmt.php","2.x\/itop-virtualization-mgmt\/pt_br.dict.itop-virtualization-mgmt.php","2.x\/itop-virtualization-mgmt\/it.dict.itop-virtualization-mgmt.php"],"version_db":"","version_code":"2.7.10","install":{"flag":1,"message":""}},"itop-welcome-itil":{"label":"ITIL skin","category":"skin","dependencies":[],"mandatory":true,"visible":false,"datamodel":["model.itop-welcome-itil.php"],"webservice":[],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-welcome-itil","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-welcome-itil\/module.itop-welcome-itil.php","dictionary":["2.x\/itop-welcome-itil\/da.dict.itop-welcome-itil.php","2.x\/itop-welcome-itil\/es_cr.dict.itop-welcome-itil.php","2.x\/itop-welcome-itil\/sk.dict.itop-welcome-itil.php","2.x\/itop-welcome-itil\/nl.dict.itop-welcome-itil.php","2.x\/itop-welcome-itil\/en.dict.itop-welcome-itil.php","2.x\/itop-welcome-itil\/fr.dict.itop-welcome-itil.php","2.x\/itop-welcome-itil\/ru.dict.itop-welcome-itil.php","2.x\/itop-welcome-itil\/ja.dict.itop-welcome-itil.php","2.x\/itop-welcome-itil\/de.dict.itop-welcome-itil.php","2.x\/itop-welcome-itil\/it.dict.itop-welcome-itil.php","2.x\/itop-welcome-itil\/tr.dict.itop-welcome-itil.php","2.x\/itop-welcome-itil\/hu.dict.itop-welcome-itil.php","2.x\/itop-welcome-itil\/zh_cn.dict.itop-welcome-itil.php","2.x\/itop-welcome-itil\/cs.dict.itop-welcome-itil.php","2.x\/itop-welcome-itil\/pt_br.dict.itop-welcome-itil.php"],"version_db":"","version_code":"2.7.10","install":{"flag":2,"message":"the module is part of the application"}},"itop-bridge-virtualization-storage":{"label":"Links between virtualization and storage","category":"business","dependencies":["itop-storage-mgmt\/2.2.0","itop-virtualization-mgmt\/2.2.0"],"mandatory":false,"visible":false,"auto_select":"SetupInfo::ModuleIsSelected(\"itop-storage-mgmt\") && SetupInfo::ModuleIsSelected(\"itop-virtualization-mgmt\")","datamodel":["model.itop-bridge-virtualization-storage.php"],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-bridge-virtualization-storage","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-bridge-virtualization-storage\/module.itop-bridge-virtualization-storage.php","version_db":"","version_code":"2.7.10","install":{"flag":1,"message":""}},"itop-change-mgmt-itil":{"label":"Change Management ITIL","category":"business","dependencies":["itop-config-mgmt\/2.2.0","itop-tickets\/2.0.0"],"mandatory":false,"visible":true,"datamodel":["model.itop-change-mgmt-itil.php"],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-change-mgmt-itil","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-change-mgmt-itil\/module.itop-change-mgmt-itil.php","dictionary":["2.x\/itop-change-mgmt-itil\/hu.dict.itop-change-mgmt-itil.php","2.x\/itop-change-mgmt-itil\/tr.dict.itop-change-mgmt-itil.php","2.x\/itop-change-mgmt-itil\/fr.dict.itop-change-mgmt-itil.php","2.x\/itop-change-mgmt-itil\/en.dict.itop-change-mgmt-itil.php","2.x\/itop-change-mgmt-itil\/cs.dict.itop-change-mgmt-itil.php","2.x\/itop-change-mgmt-itil\/da.dict.itop-change-mgmt-itil.php","2.x\/itop-change-mgmt-itil\/sk.dict.itop-change-mgmt-itil.php","2.x\/itop-change-mgmt-itil\/nl.dict.itop-change-mgmt-itil.php","2.x\/itop-change-mgmt-itil\/ja.dict.itop-change-mgmt-itil.php","2.x\/itop-change-mgmt-itil\/es_cr.dict.itop-change-mgmt-itil.php","2.x\/itop-change-mgmt-itil\/zh_cn.dict.itop-change-mgmt-itil.php","2.x\/itop-change-mgmt-itil\/de.dict.itop-change-mgmt-itil.php","2.x\/itop-change-mgmt-itil\/it.dict.itop-change-mgmt-itil.php","2.x\/itop-change-mgmt-itil\/ru.dict.itop-change-mgmt-itil.php","2.x\/itop-change-mgmt-itil\/pt_br.dict.itop-change-mgmt-itil.php"],"version_db":"","version_code":"2.7.10","install":{"flag":1,"message":""}},"itop-change-mgmt":{"label":"Change Management","category":"business","dependencies":["itop-config-mgmt\/2.2.0","itop-tickets\/2.0.0"],"mandatory":false,"visible":true,"installer":"ChangeManagementInstaller","datamodel":["model.itop-change-mgmt.php"],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-change-mgmt","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-change-mgmt\/module.itop-change-mgmt.php","dictionary":["2.x\/itop-change-mgmt\/zh_cn.dict.itop-change-mgmt.php","2.x\/itop-change-mgmt\/en.dict.itop-change-mgmt.php","2.x\/itop-change-mgmt\/tr.dict.itop-change-mgmt.php","2.x\/itop-change-mgmt\/it.dict.itop-change-mgmt.php","2.x\/itop-change-mgmt\/cs.dict.itop-change-mgmt.php","2.x\/itop-change-mgmt\/hu.dict.itop-change-mgmt.php","2.x\/itop-change-mgmt\/ja.dict.itop-change-mgmt.php","2.x\/itop-change-mgmt\/da.dict.itop-change-mgmt.php","2.x\/itop-change-mgmt\/es_cr.dict.itop-change-mgmt.php","2.x\/itop-change-mgmt\/de.dict.itop-change-mgmt.php","2.x\/itop-change-mgmt\/nl.dict.itop-change-mgmt.php","2.x\/itop-change-mgmt\/sk.dict.itop-change-mgmt.php","2.x\/itop-change-mgmt\/ru.dict.itop-change-mgmt.php","2.x\/itop-change-mgmt\/pt_br.dict.itop-change-mgmt.php","2.x\/itop-change-mgmt\/fr.dict.itop-change-mgmt.php"],"version_db":"","version_code":"2.7.10","install":{"flag":1,"message":""}},"itop-core-update":{"label":"iTop Core Update","category":"business","dependencies":["itop-files-information\/2.7.0","combodo-db-tools\/2.7.0"],"mandatory":false,"visible":true,"datamodel":["model.itop-core-update.php","src\/Service\/RunTimeEnvironmentCoreUpdater.php","src\/Service\/CoreUpdater.php","src\/Controller\/UpdateController.php","src\/Controller\/AjaxController.php"],"webservice":[],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-core-update","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-core-update\/module.itop-core-update.php","dictionary":["2.x\/itop-core-update\/ru.dict.itop-core-update.php","2.x\/itop-core-update\/de.dict.itop-core-update.php","2.x\/itop-core-update\/hu.dict.itop-core-update.php","2.x\/itop-core-update\/es_cr.dict.itop-core-update.php","2.x\/itop-core-update\/cs.dict.itop-core-update.php","2.x\/itop-core-update\/sk.dict.itop-core-update.php","2.x\/itop-core-update\/zh_cn.dict.itop-core-update.php","2.x\/itop-core-update\/fr.dict.itop-core-update.php","2.x\/itop-core-update\/da.dict.itop-core-update.php","2.x\/itop-core-update\/it.dict.itop-core-update.php","2.x\/itop-core-update\/pt_br.dict.itop-core-update.php","2.x\/itop-core-update\/en.dict.itop-core-update.php","2.x\/itop-core-update\/nl.dict.itop-core-update.php","2.x\/itop-core-update\/tr.dict.itop-core-update.php","2.x\/itop-core-update\/ja.dict.itop-core-update.php"],"version_db":"","version_code":"2.7.10","install":{"flag":1,"message":""}},"itop-incident-mgmt-itil":{"label":"Incident Management ITIL","category":"business","dependencies":["itop-config-mgmt\/2.4.0","itop-tickets\/2.4.0","itop-profiles-itil\/2.3.0"],"mandatory":false,"visible":true,"datamodel":["model.itop-incident-mgmt-itil.php"],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-incident-mgmt-itil","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-incident-mgmt-itil\/module.itop-incident-mgmt-itil.php","dictionary":["2.x\/itop-incident-mgmt-itil\/da.dict.itop-incident-mgmt-itil.php","2.x\/itop-incident-mgmt-itil\/en.dict.itop-incident-mgmt-itil.php","2.x\/itop-incident-mgmt-itil\/de.dict.itop-incident-mgmt-itil.php","2.x\/itop-incident-mgmt-itil\/zh_cn.dict.itop-incident-mgmt-itil.php","2.x\/itop-incident-mgmt-itil\/sk.dict.itop-incident-mgmt-itil.php","2.x\/itop-incident-mgmt-itil\/fr.dict.itop-incident-mgmt-itil.php","2.x\/itop-incident-mgmt-itil\/hu.dict.itop-incident-mgmt-itil.php","2.x\/itop-incident-mgmt-itil\/ja.dict.itop-incident-mgmt-itil.php","2.x\/itop-incident-mgmt-itil\/cs.dict.itop-incident-mgmt-itil.php","2.x\/itop-incident-mgmt-itil\/nl.dict.itop-incident-mgmt-itil.php","2.x\/itop-incident-mgmt-itil\/ru.dict.itop-incident-mgmt-itil.php","2.x\/itop-incident-mgmt-itil\/tr.dict.itop-incident-mgmt-itil.php","2.x\/itop-incident-mgmt-itil\/it.dict.itop-incident-mgmt-itil.php","2.x\/itop-incident-mgmt-itil\/pt_br.dict.itop-incident-mgmt-itil.php","2.x\/itop-incident-mgmt-itil\/es_cr.dict.itop-incident-mgmt-itil.php"],"version_db":"","version_code":"2.7.10","install":{"flag":1,"message":""}},"itop-knownerror-mgmt":{"label":"Known Errors Database","category":"business","dependencies":["itop-config-mgmt\/2.2.0","itop-tickets\/2.3.0"],"mandatory":false,"visible":true,"installer":"KnownErrorMgmtInstaller","datamodel":["model.itop-knownerror-mgmt.php"],"data.struct":[],"data.sample":["data.sample.faq-domains.xml"],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-knownerror-mgmt","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-knownerror-mgmt\/module.itop-knownerror-mgmt.php","dictionary":["2.x\/itop-knownerror-mgmt\/hu.dict.itop-knownerror-mgmt.php","2.x\/itop-knownerror-mgmt\/nl.dict.itop-knownerror-mgmt.php","2.x\/itop-knownerror-mgmt\/cs.dict.itop-knownerror-mgmt.php","2.x\/itop-knownerror-mgmt\/es_cr.dict.itop-knownerror-mgmt.php","2.x\/itop-knownerror-mgmt\/fr.dict.itop-knownerror-mgmt.php","2.x\/itop-knownerror-mgmt\/ru.dict.itop-knownerror-mgmt.php","2.x\/itop-knownerror-mgmt\/en.dict.itop-knownerror-mgmt.php","2.x\/itop-knownerror-mgmt\/da.dict.itop-knownerror-mgmt.php","2.x\/itop-knownerror-mgmt\/it.dict.itop-knownerror-mgmt.php","2.x\/itop-knownerror-mgmt\/sk.dict.itop-knownerror-mgmt.php","2.x\/itop-knownerror-mgmt\/pt_br.dict.itop-knownerror-mgmt.php","2.x\/itop-knownerror-mgmt\/tr.dict.itop-knownerror-mgmt.php","2.x\/itop-knownerror-mgmt\/zh_cn.dict.itop-knownerror-mgmt.php","2.x\/itop-knownerror-mgmt\/de.dict.itop-knownerror-mgmt.php","2.x\/itop-knownerror-mgmt\/ja.dict.itop-knownerror-mgmt.php"],"version_db":"","version_code":"2.7.10","install":{"flag":1,"message":""}},"itop-oauth-client":{"label":"OAuth 2.0 client","category":"business","dependencies":["itop-welcome-itil\/2.7.7,"],"mandatory":false,"visible":true,"datamodel":["vendor\/autoload.php","model.itop-oauth-client.php","src\/Service\/PopupMenuExtension.php","src\/Service\/ApplicationUIExtension.php"],"webservice":[],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-oauth-client","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-oauth-client\/module.itop-oauth-client.php","dictionary":["2.x\/itop-oauth-client\/tr.dict.itop-oauth-client.php","2.x\/itop-oauth-client\/fr.dict.itop-oauth-client.php","2.x\/itop-oauth-client\/it.dict.itop-oauth-client.php","2.x\/itop-oauth-client\/en.dict.itop-oauth-client.php","2.x\/itop-oauth-client\/cs.dict.itop-oauth-client.php","2.x\/itop-oauth-client\/sk.dict.itop-oauth-client.php","2.x\/itop-oauth-client\/ru.dict.itop-oauth-client.php","2.x\/itop-oauth-client\/zh_cn.dict.itop-oauth-client.php","2.x\/itop-oauth-client\/pt_br.dict.itop-oauth-client.php","2.x\/itop-oauth-client\/es_cr.dict.itop-oauth-client.php","2.x\/itop-oauth-client\/nl.dict.itop-oauth-client.php","2.x\/itop-oauth-client\/ja.dict.itop-oauth-client.php","2.x\/itop-oauth-client\/de.dict.itop-oauth-client.php","2.x\/itop-oauth-client\/hu.dict.itop-oauth-client.php","2.x\/itop-oauth-client\/da.dict.itop-oauth-client.php"],"version_db":"","version_code":"2.7.10","install":{"flag":1,"message":""}},"itop-problem-mgmt":{"label":"Problem Management","category":"business","dependencies":["itop-config-mgmt\/2.2.0","itop-tickets\/2.0.0"],"mandatory":false,"visible":true,"datamodel":["model.itop-problem-mgmt.php"],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-problem-mgmt","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-problem-mgmt\/module.itop-problem-mgmt.php","dictionary":["2.x\/itop-problem-mgmt\/tr.dict.itop-problem-mgmt.php","2.x\/itop-problem-mgmt\/cs.dict.itop-problem-mgmt.php","2.x\/itop-problem-mgmt\/sk.dict.itop-problem-mgmt.php","2.x\/itop-problem-mgmt\/pt_br.dict.itop-problem-mgmt.php","2.x\/itop-problem-mgmt\/es_cr.dict.itop-problem-mgmt.php","2.x\/itop-problem-mgmt\/da.dict.itop-problem-mgmt.php","2.x\/itop-problem-mgmt\/ru.dict.itop-problem-mgmt.php","2.x\/itop-problem-mgmt\/en.dict.itop-problem-mgmt.php","2.x\/itop-problem-mgmt\/hu.dict.itop-problem-mgmt.php","2.x\/itop-problem-mgmt\/fr.dict.itop-problem-mgmt.php","2.x\/itop-problem-mgmt\/nl.dict.itop-problem-mgmt.php","2.x\/itop-problem-mgmt\/ja.dict.itop-problem-mgmt.php","2.x\/itop-problem-mgmt\/de.dict.itop-problem-mgmt.php","2.x\/itop-problem-mgmt\/zh_cn.dict.itop-problem-mgmt.php","2.x\/itop-problem-mgmt\/it.dict.itop-problem-mgmt.php"],"version_db":"","version_code":"2.7.10","install":{"flag":1,"message":""}},"itop-request-mgmt-itil":{"label":"User request Management ITIL","category":"business","dependencies":["itop-config-mgmt\/2.4.0","itop-tickets\/2.4.0"],"mandatory":false,"visible":true,"datamodel":["model.itop-request-mgmt-itil.php","main.itop-request-mgmt-itil.php"],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-request-mgmt-itil","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-request-mgmt-itil\/module.itop-request-mgmt-itil.php","dictionary":["2.x\/itop-request-mgmt-itil\/ja.dict.itop-request-mgmt-itil.php","2.x\/itop-request-mgmt-itil\/hu.dict.itop-request-mgmt-itil.php","2.x\/itop-request-mgmt-itil\/fr.dict.itop-request-mgmt-itil.php","2.x\/itop-request-mgmt-itil\/nl.dict.itop-request-mgmt-itil.php","2.x\/itop-request-mgmt-itil\/ru.dict.itop-request-mgmt-itil.php","2.x\/itop-request-mgmt-itil\/zh_cn.dict.itop-request-mgmt-itil.php","2.x\/itop-request-mgmt-itil\/it.dict.itop-request-mgmt-itil.php","2.x\/itop-request-mgmt-itil\/pt_br.dict.itop-request-mgmt-itil.php","2.x\/itop-request-mgmt-itil\/sk.dict.itop-request-mgmt-itil.php","2.x\/itop-request-mgmt-itil\/tr.dict.itop-request-mgmt-itil.php","2.x\/itop-request-mgmt-itil\/es_cr.dict.itop-request-mgmt-itil.php","2.x\/itop-request-mgmt-itil\/de.dict.itop-request-mgmt-itil.php","2.x\/itop-request-mgmt-itil\/en.dict.itop-request-mgmt-itil.php","2.x\/itop-request-mgmt-itil\/cs.dict.itop-request-mgmt-itil.php","2.x\/itop-request-mgmt-itil\/da.dict.itop-request-mgmt-itil.php"],"version_db":"","version_code":"2.7.10","install":{"flag":1,"message":""}},"itop-request-mgmt":{"label":"Simple Ticket Management","category":"business","dependencies":["itop-config-mgmt\/2.4.0","itop-tickets\/2.4.0"],"mandatory":false,"visible":true,"datamodel":["model.itop-request-mgmt.php","main.itop-request-mgmt.php"],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-request-mgmt","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-request-mgmt\/module.itop-request-mgmt.php","dictionary":["2.x\/itop-request-mgmt\/tr.dict.itop-request-mgmt.php","2.x\/itop-request-mgmt\/da.dict.itop-request-mgmt.php","2.x\/itop-request-mgmt\/it.dict.itop-request-mgmt.php","2.x\/itop-request-mgmt\/fr.dict.itop-request-mgmt.php","2.x\/itop-request-mgmt\/ru.dict.itop-request-mgmt.php","2.x\/itop-request-mgmt\/cs.dict.itop-request-mgmt.php","2.x\/itop-request-mgmt\/hu.dict.itop-request-mgmt.php","2.x\/itop-request-mgmt\/en.dict.itop-request-mgmt.php","2.x\/itop-request-mgmt\/sk.dict.itop-request-mgmt.php","2.x\/itop-request-mgmt\/pt_br.dict.itop-request-mgmt.php","2.x\/itop-request-mgmt\/zh_cn.dict.itop-request-mgmt.php","2.x\/itop-request-mgmt\/de.dict.itop-request-mgmt.php","2.x\/itop-request-mgmt\/es_cr.dict.itop-request-mgmt.php","2.x\/itop-request-mgmt\/nl.dict.itop-request-mgmt.php","2.x\/itop-request-mgmt\/ja.dict.itop-request-mgmt.php"],"version_db":"","version_code":"2.7.10","install":{"flag":1,"message":""}},"itop-service-mgmt-provider":{"label":"Service Management for Service Providers","category":"business","dependencies":["itop-config-mgmt\/2.2.0","itop-tickets\/2.0.0"],"mandatory":false,"visible":true,"installer":"ServiceMgmtProviderInstaller","datamodel":["model.itop-service-mgmt-provider.php"],"data.struct":[],"data.sample":["data.sample.organizations.xml","data.sample.contracts.xml","data.sample.servicefamilies.xml","data.sample.services.xml","data.sample.serviceelements.xml","data.sample.sla.xml","data.sample.slt.xml","data.sample.sltsla.xml","data.sample.contractservice.xml","data.sample.deliverymodelcontact.xml"],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-service-mgmt-provider","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-service-mgmt-provider\/module.itop-service-mgmt-provider.php","dictionary":["2.x\/itop-service-mgmt-provider\/zh_cn.dict.itop-service-mgmt-provider.php","2.x\/itop-service-mgmt-provider\/tr.dict.itop-service-mgmt-provider.php","2.x\/itop-service-mgmt-provider\/sk.dict.itop-service-mgmt-provider.php","2.x\/itop-service-mgmt-provider\/de.dict.itop-service-mgmt-provider.php","2.x\/itop-service-mgmt-provider\/ja.dict.itop-service-mgmt-provider.php","2.x\/itop-service-mgmt-provider\/ru.dict.itop-service-mgmt-provider.php","2.x\/itop-service-mgmt-provider\/fr.dict.itop-service-mgmt-provider.php","2.x\/itop-service-mgmt-provider\/hu.dict.itop-service-mgmt-provider.php","2.x\/itop-service-mgmt-provider\/en.dict.itop-service-mgmt-provider.php","2.x\/itop-service-mgmt-provider\/it.dict.itop-service-mgmt-provider.php","2.x\/itop-service-mgmt-provider\/cs.dict.itop-service-mgmt-provider.php","2.x\/itop-service-mgmt-provider\/es_cr.dict.itop-service-mgmt-provider.php","2.x\/itop-service-mgmt-provider\/pt_br.dict.itop-service-mgmt-provider.php","2.x\/itop-service-mgmt-provider\/da.dict.itop-service-mgmt-provider.php","2.x\/itop-service-mgmt-provider\/nl.dict.itop-service-mgmt-provider.php"],"version_db":"","version_code":"2.7.10","install":{"flag":1,"message":""}},"itop-service-mgmt":{"label":"Service Management","category":"business","dependencies":["itop-config-mgmt\/2.2.0","itop-tickets\/2.0.0"],"mandatory":false,"visible":true,"installer":"ServiceMgmtInstaller","datamodel":["model.itop-service-mgmt.php"],"data.struct":[],"data.sample":["data.sample.organizations.xml","data.sample.contracts.xml","data.sample.servicefamilies.xml","data.sample.services.xml","data.sample.serviceelements.xml","data.sample.sla.xml","data.sample.slt.xml","data.sample.sltsla.xml","data.sample.contractservice.xml","data.sample.deliverymodelcontact.xml"],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-service-mgmt","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-service-mgmt\/module.itop-service-mgmt.php","dictionary":["2.x\/itop-service-mgmt\/hu.dict.itop-service-mgmt.php","2.x\/itop-service-mgmt\/es_cr.dict.itop-service-mgmt.php","2.x\/itop-service-mgmt\/nl.dict.itop-service-mgmt.php","2.x\/itop-service-mgmt\/sk.dict.itop-service-mgmt.php","2.x\/itop-service-mgmt\/it.dict.itop-service-mgmt.php","2.x\/itop-service-mgmt\/da.dict.itop-service-mgmt.php","2.x\/itop-service-mgmt\/zh_cn.dict.itop-service-mgmt.php","2.x\/itop-service-mgmt\/tr.dict.itop-service-mgmt.php","2.x\/itop-service-mgmt\/en.dict.itop-service-mgmt.php","2.x\/itop-service-mgmt\/cs.dict.itop-service-mgmt.php","2.x\/itop-service-mgmt\/de.dict.itop-service-mgmt.php","2.x\/itop-service-mgmt\/ja.dict.itop-service-mgmt.php","2.x\/itop-service-mgmt\/ru.dict.itop-service-mgmt.php","2.x\/itop-service-mgmt\/pt_br.dict.itop-service-mgmt.php","2.x\/itop-service-mgmt\/fr.dict.itop-service-mgmt.php"],"version_db":"","version_code":"2.7.10","install":{"flag":1,"message":""}},"itop-full-itil":{"label":"Bridge - Request management ITIL + Incident management ITIL","category":"business","dependencies":["itop-request-mgmt-itil\/2.3.0","itop-incident-mgmt-itil\/2.3.0"],"mandatory":false,"visible":false,"auto_select":"SetupInfo::ModuleIsSelected(\"itop-request-mgmt-itil\") && SetupInfo::ModuleIsSelected(\"itop-incident-mgmt-itil\")","datamodel":[],"webservice":[],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-full-itil","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-full-itil\/module.itop-full-itil.php","version_db":"","version_code":"2.7.10","install":{"flag":1,"message":""}}} +{"_Root_":{"installed_version":"","available_version":"2.7.0-dev-svn","name_code":"iTop"},"authent-cas":{"label":"CAS SSO","category":"authentication","dependencies":[],"mandatory":true,"visible":true,"datamodel":["model.authent-cas.php","vendor\/autoload.php","src\/CASLoginExtension.php"],"webservice":[],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":{"cas_debug":false,"cas_host":"","cas_port":"","cas_context":"","cas_version":"","service_base_url":""},"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/authent-cas","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/authent-cas\/module.authent-cas.php","dictionary":["2.x\/authent-cas\/de.dict.authent-cas.php","2.x\/authent-cas\/cs.dict.authent-cas.php","2.x\/authent-cas\/nl.dict.authent-cas.php","2.x\/authent-cas\/da.dict.authent-cas.php","2.x\/authent-cas\/tr.dict.authent-cas.php","2.x\/authent-cas\/ru.dict.authent-cas.php","2.x\/authent-cas\/ja.dict.authent-cas.php","2.x\/authent-cas\/es_cr.dict.authent-cas.php","2.x\/authent-cas\/it.dict.authent-cas.php","2.x\/authent-cas\/pt_br.dict.authent-cas.php","2.x\/authent-cas\/sk.dict.authent-cas.php","2.x\/authent-cas\/hu.dict.authent-cas.php","2.x\/authent-cas\/zh_cn.dict.authent-cas.php","2.x\/authent-cas\/en.dict.authent-cas.php","2.x\/authent-cas\/fr.dict.authent-cas.php"],"installed_version":"","available_version":"2.7.10","install":{"flag":2,"message":"the module is part of the application"}},"authent-external":{"label":"External user authentication","category":"authentication","dependencies":[],"mandatory":false,"visible":true,"datamodel":["model.authent-external.php"],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/authent-external","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/authent-external\/module.authent-external.php","dictionary":["2.x\/authent-external\/fr.dict.authent-external.php","2.x\/authent-external\/de.dict.authent-external.php","2.x\/authent-external\/zh_cn.dict.authent-external.php","2.x\/authent-external\/tr.dict.authent-external.php","2.x\/authent-external\/pt_br.dict.authent-external.php","2.x\/authent-external\/da.dict.authent-external.php","2.x\/authent-external\/ru.dict.authent-external.php","2.x\/authent-external\/cs.dict.authent-external.php","2.x\/authent-external\/it.dict.authent-external.php","2.x\/authent-external\/en.dict.authent-external.php","2.x\/authent-external\/hu.dict.authent-external.php","2.x\/authent-external\/sk.dict.authent-external.php","2.x\/authent-external\/ja.dict.authent-external.php","2.x\/authent-external\/nl.dict.authent-external.php","2.x\/authent-external\/es_cr.dict.authent-external.php"],"installed_version":"","available_version":"2.7.10","install":{"flag":1,"message":""}},"authent-ldap":{"label":"User authentication based on LDAP","category":"authentication","dependencies":[],"mandatory":false,"visible":true,"datamodel":["model.authent-ldap.php"],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":{"host":"localhost","port":389,"default_user":"","default_pwd":"","base_dn":"dc=yourcompany,dc=com","user_query":"(&(uid=%1$s)(inetuserstatus=ACTIVE))","options":{"17":3,"8":0},"start_tls":false,"debug":false},"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/authent-ldap","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/authent-ldap\/module.authent-ldap.php","dictionary":["2.x\/authent-ldap\/en.dict.authent-ldap.php","2.x\/authent-ldap\/ru.dict.authent-ldap.php","2.x\/authent-ldap\/cs.dict.authent-ldap.php","2.x\/authent-ldap\/es_cr.dict.authent-ldap.php","2.x\/authent-ldap\/zh_cn.dict.authent-ldap.php","2.x\/authent-ldap\/pt_br.dict.authent-ldap.php","2.x\/authent-ldap\/it.dict.authent-ldap.php","2.x\/authent-ldap\/tr.dict.authent-ldap.php","2.x\/authent-ldap\/fr.dict.authent-ldap.php","2.x\/authent-ldap\/de.dict.authent-ldap.php","2.x\/authent-ldap\/da.dict.authent-ldap.php","2.x\/authent-ldap\/nl.dict.authent-ldap.php","2.x\/authent-ldap\/hu.dict.authent-ldap.php","2.x\/authent-ldap\/sk.dict.authent-ldap.php","2.x\/authent-ldap\/ja.dict.authent-ldap.php"],"installed_version":"","available_version":"2.7.10","install":{"flag":1,"message":""}},"authent-local":{"label":"User authentication based on the local DB","category":"authentication","dependencies":[],"mandatory":true,"visible":true,"datamodel":["model.authent-local.php"],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/authent-local","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/authent-local\/module.authent-local.php","dictionary":["2.x\/authent-local\/hu.dict.authent-local.php","2.x\/authent-local\/de.dict.authent-local.php","2.x\/authent-local\/ja.dict.authent-local.php","2.x\/authent-local\/fr.dict.authent-local.php","2.x\/authent-local\/es_cr.dict.authent-local.php","2.x\/authent-local\/it.dict.authent-local.php","2.x\/authent-local\/tr.dict.authent-local.php","2.x\/authent-local\/da.dict.authent-local.php","2.x\/authent-local\/sk.dict.authent-local.php","2.x\/authent-local\/ru.dict.authent-local.php","2.x\/authent-local\/nl.dict.authent-local.php","2.x\/authent-local\/zh_cn.dict.authent-local.php","2.x\/authent-local\/cs.dict.authent-local.php","2.x\/authent-local\/en.dict.authent-local.php","2.x\/authent-local\/pt_br.dict.authent-local.php"],"installed_version":"","available_version":"2.7.10","install":{"flag":2,"message":"the module is part of the application"}},"combodo-db-tools":{"label":"Database maintenance tools","category":"business","dependencies":[],"mandatory":false,"visible":true,"datamodel":["model.combodo-db-tools.php","src\/Service\/DBToolsUtils.php","src\/Service\/DBAnalyzerUtils.php"],"webservice":[],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/combodo-db-tools","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/combodo-db-tools\/module.combodo-db-tools.php","dictionary":["2.x\/combodo-db-tools\/en.dict.combodo-db-tools.php","2.x\/combodo-db-tools\/pt_br.dict.combodo-db-tools.php","2.x\/combodo-db-tools\/zh_cn.dict.combodo-db-tools.php","2.x\/combodo-db-tools\/nl.dict.combodo-db-tools.php","2.x\/combodo-db-tools\/ru.dict.combodo-db-tools.php","2.x\/combodo-db-tools\/es_cr.dict.combodo-db-tools.php","2.x\/combodo-db-tools\/tr.dict.combodo-db-tools.php","2.x\/combodo-db-tools\/da.dict.combodo-db-tools.php","2.x\/combodo-db-tools\/ja.dict.combodo-db-tools.php","2.x\/combodo-db-tools\/de.dict.combodo-db-tools.php","2.x\/combodo-db-tools\/hu.dict.combodo-db-tools.php","2.x\/combodo-db-tools\/fr.dict.combodo-db-tools.php","2.x\/combodo-db-tools\/it.dict.combodo-db-tools.php","2.x\/combodo-db-tools\/sk.dict.combodo-db-tools.php","2.x\/combodo-db-tools\/cs.dict.combodo-db-tools.php"],"installed_version":"","available_version":"2.7.10","install":{"flag":1,"message":""}},"combodo-monitoring":{"label":"Combodo Monitoring","category":"monitoring","dependencies":[],"mandatory":false,"visible":true,"datamodel":["vendor\/autoload.php"],"webservice":[],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"\/var\/www\/html\/iTop\/extensions\/combodo-monitoring","module_file":"\/var\/www\/html\/iTop\/extensions\/combodo-monitoring\/module.combodo-monitoring.php","installed_version":"","available_version":"1.0.7","install":{"flag":1,"message":""}},"itop-attachments":{"label":"Tickets Attachments","category":"business","dependencies":[],"mandatory":false,"visible":true,"installer":"AttachmentInstaller","datamodel":["model.itop-attachments.php","main.itop-attachments.php","renderers.itop-attachments.php"],"webservice":[],"dictionary":["2.x\/itop-attachments\/cs.dict.itop-attachments.php","2.x\/itop-attachments\/ja.dict.itop-attachments.php","2.x\/itop-attachments\/es_cr.dict.itop-attachments.php","2.x\/itop-attachments\/ru.dict.itop-attachments.php","2.x\/itop-attachments\/it.dict.itop-attachments.php","2.x\/itop-attachments\/zh_cn.dict.itop-attachments.php","2.x\/itop-attachments\/hu.dict.itop-attachments.php","2.x\/itop-attachments\/da.dict.itop-attachments.php","2.x\/itop-attachments\/en.dict.itop-attachments.php","2.x\/itop-attachments\/sk.dict.itop-attachments.php","2.x\/itop-attachments\/pt_br.dict.itop-attachments.php","2.x\/itop-attachments\/fr.dict.itop-attachments.php","2.x\/itop-attachments\/de.dict.itop-attachments.php","2.x\/itop-attachments\/tr.dict.itop-attachments.php","2.x\/itop-attachments\/nl.dict.itop-attachments.php"],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":{"allowed_classes":["Ticket"],"position":"relations","preview_max_width":290},"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-attachments","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-attachments\/module.itop-attachments.php","installed_version":"","available_version":"2.7.10","install":{"flag":1,"message":""}},"itop-backup":{"label":"Backup utilities","category":"Application management","dependencies":[],"mandatory":true,"visible":false,"datamodel":["main.itop-backup.php","model.itop-backup.php"],"webservice":[],"dictionary":["en.dict.itop-backup.php","fr.dict.itop-backup.php","2.x\/itop-backup\/cs.dict.itop-backup.php","2.x\/itop-backup\/es_cr.dict.itop-backup.php","2.x\/itop-backup\/fr.dict.itop-backup.php","2.x\/itop-backup\/de.dict.itop-backup.php","2.x\/itop-backup\/ja.dict.itop-backup.php","2.x\/itop-backup\/en.dict.itop-backup.php","2.x\/itop-backup\/hu.dict.itop-backup.php","2.x\/itop-backup\/nl.dict.itop-backup.php","2.x\/itop-backup\/it.dict.itop-backup.php","2.x\/itop-backup\/sk.dict.itop-backup.php","2.x\/itop-backup\/ru.dict.itop-backup.php","2.x\/itop-backup\/tr.dict.itop-backup.php","2.x\/itop-backup\/pt_br.dict.itop-backup.php","2.x\/itop-backup\/da.dict.itop-backup.php","2.x\/itop-backup\/zh_cn.dict.itop-backup.php"],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":{"mysql_bindir":"","week_days":"monday, tuesday, wednesday, thursday, friday","time":"23:30","retention_count":5,"enabled":true,"itop_backup_incident":""},"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-backup","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-backup\/module.itop-backup.php","installed_version":"","available_version":"2.7.10","install":{"flag":2,"message":"the module is part of the application"}},"itop-config-mgmt":{"label":"Configuration Management (CMDB)","category":"business","dependencies":[],"mandatory":true,"visible":true,"installer":"ConfigMgmtInstaller","datamodel":["model.itop-config-mgmt.php","main.itop-config-mgmt.php"],"data.struct":[],"data.sample":["data.sample.organizations.xml","data.sample.brand.xml","data.sample.model.xml","data.sample.osfamily.xml","data.sample.osversion.xml","data.sample.networkdevicetype.xml","data.sample.contacttype.xml","data.sample.locations.xml","data.sample.persons.xml","data.sample.teams.xml","data.sample.contactteam.xml","data.sample.servers.xml","data.sample.nw-devices.xml","data.sample.software.xml","data.sample.dbserver.xml","data.sample.dbschema.xml","data.sample.webserver.xml","data.sample.webapp.xml","data.sample.applications.xml","data.sample.applicationsolutionci.xml"],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-config-mgmt","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-config-mgmt\/module.itop-config-mgmt.php","dictionary":["2.x\/itop-config-mgmt\/ru.dict.itop-config-mgmt.php","2.x\/itop-config-mgmt\/tr.dict.itop-config-mgmt.php","2.x\/itop-config-mgmt\/it.dict.itop-config-mgmt.php","2.x\/itop-config-mgmt\/de.dict.itop-config-mgmt.php","2.x\/itop-config-mgmt\/fr.dict.itop-config-mgmt.php","2.x\/itop-config-mgmt\/hu.dict.itop-config-mgmt.php","2.x\/itop-config-mgmt\/nl.dict.itop-config-mgmt.php","2.x\/itop-config-mgmt\/en.dict.itop-config-mgmt.php","2.x\/itop-config-mgmt\/cs.dict.itop-config-mgmt.php","2.x\/itop-config-mgmt\/ja.dict.itop-config-mgmt.php","2.x\/itop-config-mgmt\/sk.dict.itop-config-mgmt.php","2.x\/itop-config-mgmt\/zh_cn.dict.itop-config-mgmt.php","2.x\/itop-config-mgmt\/da.dict.itop-config-mgmt.php","2.x\/itop-config-mgmt\/pt_br.dict.itop-config-mgmt.php","2.x\/itop-config-mgmt\/es_cr.dict.itop-config-mgmt.php"],"installed_version":"","available_version":"2.7.10","install":{"flag":2,"message":"the module is part of the application"}},"itop-config":{"label":"Configuration editor","category":"Application management","dependencies":[],"mandatory":true,"visible":false,"datamodel":["model.itop-config.php","src\/Validator\/ConfigNodesVisitor.php","src\/Validator\/iTopConfigAstValidator.php","src\/Validator\/iTopConfigSyntaxValidator.php"],"webservice":[],"dictionary":["en.dict.itop-config.php","fr.dict.itop-config.php","2.x\/itop-config\/ru.dict.itop-config.php","2.x\/itop-config\/en.dict.itop-config.php","2.x\/itop-config\/sk.dict.itop-config.php","2.x\/itop-config\/cs.dict.itop-config.php","2.x\/itop-config\/de.dict.itop-config.php","2.x\/itop-config\/zh_cn.dict.itop-config.php","2.x\/itop-config\/nl.dict.itop-config.php","2.x\/itop-config\/es_cr.dict.itop-config.php","2.x\/itop-config\/da.dict.itop-config.php","2.x\/itop-config\/ja.dict.itop-config.php","2.x\/itop-config\/pt_br.dict.itop-config.php","2.x\/itop-config\/tr.dict.itop-config.php","2.x\/itop-config\/hu.dict.itop-config.php","2.x\/itop-config\/it.dict.itop-config.php","2.x\/itop-config\/fr.dict.itop-config.php"],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-config","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-config\/module.itop-config.php","installed_version":"","available_version":"2.7.10","install":{"flag":2,"message":"the module is part of the application"}},"itop-datacenter-mgmt":{"label":"Datacenter Management","category":"business","dependencies":["itop-config-mgmt\/2.2.0"],"mandatory":false,"visible":true,"datamodel":["model.itop-datacenter-mgmt.php"],"webservice":[],"data.struct":[],"data.sample":["data.sample.racks.xml"],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-datacenter-mgmt","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-datacenter-mgmt\/module.itop-datacenter-mgmt.php","dictionary":["2.x\/itop-datacenter-mgmt\/tr.dict.itop-datacenter-mgmt.php","2.x\/itop-datacenter-mgmt\/ja.dict.itop-datacenter-mgmt.php","2.x\/itop-datacenter-mgmt\/sk.dict.itop-datacenter-mgmt.php","2.x\/itop-datacenter-mgmt\/da.dict.itop-datacenter-mgmt.php","2.x\/itop-datacenter-mgmt\/es_cr.dict.itop-datacenter-mgmt.php","2.x\/itop-datacenter-mgmt\/ru.dict.itop-datacenter-mgmt.php","2.x\/itop-datacenter-mgmt\/en.dict.itop-datacenter-mgmt.php","2.x\/itop-datacenter-mgmt\/it.dict.itop-datacenter-mgmt.php","2.x\/itop-datacenter-mgmt\/zh_cn.dict.itop-datacenter-mgmt.php","2.x\/itop-datacenter-mgmt\/de.dict.itop-datacenter-mgmt.php","2.x\/itop-datacenter-mgmt\/hu.dict.itop-datacenter-mgmt.php","2.x\/itop-datacenter-mgmt\/cs.dict.itop-datacenter-mgmt.php","2.x\/itop-datacenter-mgmt\/fr.dict.itop-datacenter-mgmt.php","2.x\/itop-datacenter-mgmt\/pt_br.dict.itop-datacenter-mgmt.php","2.x\/itop-datacenter-mgmt\/nl.dict.itop-datacenter-mgmt.php"],"installed_version":"","available_version":"2.7.10","install":{"flag":1,"message":""}},"itop-endusers-devices":{"label":"End-user Devices Management","category":"business","dependencies":["itop-config-mgmt\/2.2.0"],"mandatory":false,"visible":true,"installer":"EndUserMgmtInstaller","datamodel":["model.itop-endusers-devices.php"],"webservice":[],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-endusers-devices","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-endusers-devices\/module.itop-endusers-devices.php","dictionary":["2.x\/itop-endusers-devices\/cs.dict.itop-endusers-devices.php","2.x\/itop-endusers-devices\/en.dict.itop-endusers-devices.php","2.x\/itop-endusers-devices\/ru.dict.itop-endusers-devices.php","2.x\/itop-endusers-devices\/it.dict.itop-endusers-devices.php","2.x\/itop-endusers-devices\/sk.dict.itop-endusers-devices.php","2.x\/itop-endusers-devices\/es_cr.dict.itop-endusers-devices.php","2.x\/itop-endusers-devices\/de.dict.itop-endusers-devices.php","2.x\/itop-endusers-devices\/fr.dict.itop-endusers-devices.php","2.x\/itop-endusers-devices\/tr.dict.itop-endusers-devices.php","2.x\/itop-endusers-devices\/hu.dict.itop-endusers-devices.php","2.x\/itop-endusers-devices\/da.dict.itop-endusers-devices.php","2.x\/itop-endusers-devices\/zh_cn.dict.itop-endusers-devices.php","2.x\/itop-endusers-devices\/nl.dict.itop-endusers-devices.php","2.x\/itop-endusers-devices\/ja.dict.itop-endusers-devices.php","2.x\/itop-endusers-devices\/pt_br.dict.itop-endusers-devices.php"],"installed_version":"","available_version":"2.7.10","install":{"flag":1,"message":""}},"itop-files-information":{"label":"iTop files information","category":"business","dependencies":[],"mandatory":false,"visible":false,"datamodel":["model.itop-files-information.php","src\/Service\/FilesInformation.php","src\/Service\/FilesInformationException.php","src\/Service\/FilesInformationUtils.php","src\/Service\/FilesIntegrity.php"],"webservice":[],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-files-information","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-files-information\/module.itop-files-information.php","dictionary":["2.x\/itop-files-information\/sk.dict.itop-files-information.php","2.x\/itop-files-information\/cs.dict.itop-files-information.php","2.x\/itop-files-information\/ja.dict.itop-files-information.php","2.x\/itop-files-information\/hu.dict.itop-files-information.php","2.x\/itop-files-information\/fr.dict.itop-files-information.php","2.x\/itop-files-information\/pt_br.dict.itop-files-information.php","2.x\/itop-files-information\/es_cr.dict.itop-files-information.php","2.x\/itop-files-information\/tr.dict.itop-files-information.php","2.x\/itop-files-information\/zh_cn.dict.itop-files-information.php","2.x\/itop-files-information\/en.dict.itop-files-information.php","2.x\/itop-files-information\/da.dict.itop-files-information.php","2.x\/itop-files-information\/de.dict.itop-files-information.php","2.x\/itop-files-information\/nl.dict.itop-files-information.php","2.x\/itop-files-information\/it.dict.itop-files-information.php","2.x\/itop-files-information\/ru.dict.itop-files-information.php"],"installed_version":"","available_version":"2.7.10","install":{"flag":1,"message":""}},"itop-hub-connector":{"label":"iTop Hub Connector","category":"business","dependencies":["itop-config-mgmt\/2.4.0"],"mandatory":false,"visible":true,"datamodel":["menus.php","hubnewsroomprovider.class.inc.php","model.itop-hub-connector.php"],"webservice":[],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-hub-connector","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-hub-connector\/module.itop-hub-connector.php","dictionary":["2.x\/itop-hub-connector\/it.dict.itop-hub-connector.php","2.x\/itop-hub-connector\/zh_cn.dict.itop-hub-connector.php","2.x\/itop-hub-connector\/sk.dict.itop-hub-connector.php","2.x\/itop-hub-connector\/cs.dict.itop-hub-connector.php","2.x\/itop-hub-connector\/fr.dict.itop-hub-connector.php","2.x\/itop-hub-connector\/hu.dict.itop-hub-connector.php","2.x\/itop-hub-connector\/ru.dict.itop-hub-connector.php","2.x\/itop-hub-connector\/ja.dict.itop-hub-connector.php","2.x\/itop-hub-connector\/en.dict.itop-hub-connector.php","2.x\/itop-hub-connector\/es_cr.dict.itop-hub-connector.php","2.x\/itop-hub-connector\/tr.dict.itop-hub-connector.php","2.x\/itop-hub-connector\/nl.dict.itop-hub-connector.php","2.x\/itop-hub-connector\/de.dict.itop-hub-connector.php","2.x\/itop-hub-connector\/pt_br.dict.itop-hub-connector.php","2.x\/itop-hub-connector\/da.dict.itop-hub-connector.php"],"installed_version":"","available_version":"2.7.10","install":{"flag":1,"message":""}},"itop-portal-base":{"label":"Portal Development Library","category":"Portal","dependencies":[],"mandatory":true,"visible":false,"datamodel":["portal\/vendor\/autoload.php","model.itop-portal-base.php"],"webservice":[],"dictionary":["2.x\/itop-portal-base\/hu.dict.itop-portal-base.php","2.x\/itop-portal-base\/ja.dict.itop-portal-base.php","2.x\/itop-portal-base\/cs.dict.itop-portal-base.php","2.x\/itop-portal-base\/zh_cn.dict.itop-portal-base.php","2.x\/itop-portal-base\/tr.dict.itop-portal-base.php","2.x\/itop-portal-base\/pt_br.dict.itop-portal-base.php","2.x\/itop-portal-base\/nl.dict.itop-portal-base.php","2.x\/itop-portal-base\/it.dict.itop-portal-base.php","2.x\/itop-portal-base\/es_cr.dict.itop-portal-base.php","2.x\/itop-portal-base\/fr.dict.itop-portal-base.php","2.x\/itop-portal-base\/ru.dict.itop-portal-base.php","2.x\/itop-portal-base\/de.dict.itop-portal-base.php","2.x\/itop-portal-base\/da.dict.itop-portal-base.php","2.x\/itop-portal-base\/en.dict.itop-portal-base.php","2.x\/itop-portal-base\/sk.dict.itop-portal-base.php"],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-portal-base","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-portal-base\/module.itop-portal-base.php","installed_version":"","available_version":"2.7.10","install":{"flag":2,"message":"the module is part of the application"}},"itop-portal":{"label":"Enhanced Customer Portal","category":"Portal","dependencies":["itop-portal-base\/2.7.0"],"mandatory":false,"visible":true,"datamodel":["main.itop-portal.php","model.itop-portal.php"],"webservice":[],"dictionary":[],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-portal","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-portal\/module.itop-portal.php","installed_version":"","available_version":"2.7.10","install":{"flag":1,"message":""}},"itop-profiles-itil":{"label":"Create standard ITIL profiles","category":"create_profiles","dependencies":[],"mandatory":true,"visible":false,"datamodel":["model.itop-profiles-itil.php"],"webservice":[],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-profiles-itil","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-profiles-itil\/module.itop-profiles-itil.php","installed_version":"","available_version":"2.7.10","install":{"flag":2,"message":"the module is part of the application"}},"itop-sla-computation":{"label":"SLA Computation","category":"sla","dependencies":[],"mandatory":true,"visible":false,"datamodel":["main.itop-sla-computation.php"],"webservice":[],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-sla-computation","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-sla-computation\/module.itop-sla-computation.php","dictionary":["2.x\/itop-sla-computation\/de.dict.itop-sla-computation.php","2.x\/itop-sla-computation\/it.dict.itop-sla-computation.php","2.x\/itop-sla-computation\/tr.dict.itop-sla-computation.php","2.x\/itop-sla-computation\/nl.dict.itop-sla-computation.php","2.x\/itop-sla-computation\/zh_cn.dict.itop-sla-computation.php","2.x\/itop-sla-computation\/hu.dict.itop-sla-computation.php","2.x\/itop-sla-computation\/ja.dict.itop-sla-computation.php","2.x\/itop-sla-computation\/pt_br.dict.itop-sla-computation.php","2.x\/itop-sla-computation\/es_cr.dict.itop-sla-computation.php","2.x\/itop-sla-computation\/fr.dict.itop-sla-computation.php","2.x\/itop-sla-computation\/cs.dict.itop-sla-computation.php","2.x\/itop-sla-computation\/sk.dict.itop-sla-computation.php","2.x\/itop-sla-computation\/da.dict.itop-sla-computation.php","2.x\/itop-sla-computation\/en.dict.itop-sla-computation.php","2.x\/itop-sla-computation\/ru.dict.itop-sla-computation.php"],"installed_version":"","available_version":"2.7.10","install":{"flag":2,"message":"the module is part of the application"}},"itop-storage-mgmt":{"label":"Advanced Storage Management","category":"business","dependencies":["itop-config-mgmt\/2.4.0"],"mandatory":false,"visible":true,"installer":"StorageMgmtInstaller","datamodel":["model.itop-storage-mgmt.php"],"webservice":[],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-storage-mgmt","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-storage-mgmt\/module.itop-storage-mgmt.php","dictionary":["2.x\/itop-storage-mgmt\/en.dict.itop-storage-mgmt.php","2.x\/itop-storage-mgmt\/cs.dict.itop-storage-mgmt.php","2.x\/itop-storage-mgmt\/ja.dict.itop-storage-mgmt.php","2.x\/itop-storage-mgmt\/da.dict.itop-storage-mgmt.php","2.x\/itop-storage-mgmt\/pt_br.dict.itop-storage-mgmt.php","2.x\/itop-storage-mgmt\/it.dict.itop-storage-mgmt.php","2.x\/itop-storage-mgmt\/nl.dict.itop-storage-mgmt.php","2.x\/itop-storage-mgmt\/fr.dict.itop-storage-mgmt.php","2.x\/itop-storage-mgmt\/tr.dict.itop-storage-mgmt.php","2.x\/itop-storage-mgmt\/es_cr.dict.itop-storage-mgmt.php","2.x\/itop-storage-mgmt\/sk.dict.itop-storage-mgmt.php","2.x\/itop-storage-mgmt\/zh_cn.dict.itop-storage-mgmt.php","2.x\/itop-storage-mgmt\/de.dict.itop-storage-mgmt.php","2.x\/itop-storage-mgmt\/hu.dict.itop-storage-mgmt.php","2.x\/itop-storage-mgmt\/ru.dict.itop-storage-mgmt.php"],"installed_version":"","available_version":"2.7.10","install":{"flag":1,"message":""}},"itop-tickets":{"label":"Tickets Management","category":"business","dependencies":["itop-config-mgmt\/2.4.0"],"mandatory":true,"visible":false,"installer":"TicketsInstaller","datamodel":["main.itop-tickets.php","model.itop-tickets.php"],"data.struct":[],"data.sample":[],"doc.manual_setup":"\/documentation\/itop-tickets.htm","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-tickets","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-tickets\/module.itop-tickets.php","dictionary":["2.x\/itop-tickets\/cs.dict.itop-tickets.php","2.x\/itop-tickets\/da.dict.itop-tickets.php","2.x\/itop-tickets\/es_cr.dict.itop-tickets.php","2.x\/itop-tickets\/tr.dict.itop-tickets.php","2.x\/itop-tickets\/nl.dict.itop-tickets.php","2.x\/itop-tickets\/it.dict.itop-tickets.php","2.x\/itop-tickets\/en.dict.itop-tickets.php","2.x\/itop-tickets\/pt_br.dict.itop-tickets.php","2.x\/itop-tickets\/fr.dict.itop-tickets.php","2.x\/itop-tickets\/sk.dict.itop-tickets.php","2.x\/itop-tickets\/ja.dict.itop-tickets.php","2.x\/itop-tickets\/ru.dict.itop-tickets.php","2.x\/itop-tickets\/hu.dict.itop-tickets.php","2.x\/itop-tickets\/de.dict.itop-tickets.php","2.x\/itop-tickets\/zh_cn.dict.itop-tickets.php"],"installed_version":"","available_version":"2.7.10","install":{"flag":2,"message":"the module is part of the application"}},"itop-virtualization-mgmt":{"label":"Virtualization Management","category":"business","dependencies":["itop-config-mgmt\/2.4.0"],"mandatory":false,"visible":true,"datamodel":["model.itop-virtualization-mgmt.php"],"webservice":[],"data.struct":[],"data.sample":["data.sample.farm.xml","data.sample.hypervisor.xml","data.sample.vm.xml","data.sample.dbserver.xml","data.sample.dbschema.xml","data.sample.webserver.xml","data.sample.webapp.xml","data.sample.applicationsolutionci.xml"],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-virtualization-mgmt","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-virtualization-mgmt\/module.itop-virtualization-mgmt.php","dictionary":["2.x\/itop-virtualization-mgmt\/de.dict.itop-virtualization-mgmt.php","2.x\/itop-virtualization-mgmt\/nl.dict.itop-virtualization-mgmt.php","2.x\/itop-virtualization-mgmt\/ja.dict.itop-virtualization-mgmt.php","2.x\/itop-virtualization-mgmt\/zh_cn.dict.itop-virtualization-mgmt.php","2.x\/itop-virtualization-mgmt\/ru.dict.itop-virtualization-mgmt.php","2.x\/itop-virtualization-mgmt\/sk.dict.itop-virtualization-mgmt.php","2.x\/itop-virtualization-mgmt\/tr.dict.itop-virtualization-mgmt.php","2.x\/itop-virtualization-mgmt\/fr.dict.itop-virtualization-mgmt.php","2.x\/itop-virtualization-mgmt\/cs.dict.itop-virtualization-mgmt.php","2.x\/itop-virtualization-mgmt\/da.dict.itop-virtualization-mgmt.php","2.x\/itop-virtualization-mgmt\/hu.dict.itop-virtualization-mgmt.php","2.x\/itop-virtualization-mgmt\/es_cr.dict.itop-virtualization-mgmt.php","2.x\/itop-virtualization-mgmt\/en.dict.itop-virtualization-mgmt.php","2.x\/itop-virtualization-mgmt\/pt_br.dict.itop-virtualization-mgmt.php","2.x\/itop-virtualization-mgmt\/it.dict.itop-virtualization-mgmt.php"],"installed_version":"","available_version":"2.7.10","install":{"flag":1,"message":""}},"itop-welcome-itil":{"label":"ITIL skin","category":"skin","dependencies":[],"mandatory":true,"visible":false,"datamodel":["model.itop-welcome-itil.php"],"webservice":[],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-welcome-itil","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-welcome-itil\/module.itop-welcome-itil.php","dictionary":["2.x\/itop-welcome-itil\/da.dict.itop-welcome-itil.php","2.x\/itop-welcome-itil\/es_cr.dict.itop-welcome-itil.php","2.x\/itop-welcome-itil\/sk.dict.itop-welcome-itil.php","2.x\/itop-welcome-itil\/nl.dict.itop-welcome-itil.php","2.x\/itop-welcome-itil\/en.dict.itop-welcome-itil.php","2.x\/itop-welcome-itil\/fr.dict.itop-welcome-itil.php","2.x\/itop-welcome-itil\/ru.dict.itop-welcome-itil.php","2.x\/itop-welcome-itil\/ja.dict.itop-welcome-itil.php","2.x\/itop-welcome-itil\/de.dict.itop-welcome-itil.php","2.x\/itop-welcome-itil\/it.dict.itop-welcome-itil.php","2.x\/itop-welcome-itil\/tr.dict.itop-welcome-itil.php","2.x\/itop-welcome-itil\/hu.dict.itop-welcome-itil.php","2.x\/itop-welcome-itil\/zh_cn.dict.itop-welcome-itil.php","2.x\/itop-welcome-itil\/cs.dict.itop-welcome-itil.php","2.x\/itop-welcome-itil\/pt_br.dict.itop-welcome-itil.php"],"installed_version":"","available_version":"2.7.10","install":{"flag":2,"message":"the module is part of the application"}},"itop-bridge-virtualization-storage":{"label":"Links between virtualization and storage","category":"business","dependencies":["itop-storage-mgmt\/2.2.0","itop-virtualization-mgmt\/2.2.0"],"mandatory":false,"visible":false,"auto_select":"SetupInfo::ModuleIsSelected(\"itop-storage-mgmt\") && SetupInfo::ModuleIsSelected(\"itop-virtualization-mgmt\")","datamodel":["model.itop-bridge-virtualization-storage.php"],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-bridge-virtualization-storage","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-bridge-virtualization-storage\/module.itop-bridge-virtualization-storage.php","installed_version":"","available_version":"2.7.10","install":{"flag":1,"message":""}},"itop-change-mgmt-itil":{"label":"Change Management ITIL","category":"business","dependencies":["itop-config-mgmt\/2.2.0","itop-tickets\/2.0.0"],"mandatory":false,"visible":true,"datamodel":["model.itop-change-mgmt-itil.php"],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-change-mgmt-itil","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-change-mgmt-itil\/module.itop-change-mgmt-itil.php","dictionary":["2.x\/itop-change-mgmt-itil\/hu.dict.itop-change-mgmt-itil.php","2.x\/itop-change-mgmt-itil\/tr.dict.itop-change-mgmt-itil.php","2.x\/itop-change-mgmt-itil\/fr.dict.itop-change-mgmt-itil.php","2.x\/itop-change-mgmt-itil\/en.dict.itop-change-mgmt-itil.php","2.x\/itop-change-mgmt-itil\/cs.dict.itop-change-mgmt-itil.php","2.x\/itop-change-mgmt-itil\/da.dict.itop-change-mgmt-itil.php","2.x\/itop-change-mgmt-itil\/sk.dict.itop-change-mgmt-itil.php","2.x\/itop-change-mgmt-itil\/nl.dict.itop-change-mgmt-itil.php","2.x\/itop-change-mgmt-itil\/ja.dict.itop-change-mgmt-itil.php","2.x\/itop-change-mgmt-itil\/es_cr.dict.itop-change-mgmt-itil.php","2.x\/itop-change-mgmt-itil\/zh_cn.dict.itop-change-mgmt-itil.php","2.x\/itop-change-mgmt-itil\/de.dict.itop-change-mgmt-itil.php","2.x\/itop-change-mgmt-itil\/it.dict.itop-change-mgmt-itil.php","2.x\/itop-change-mgmt-itil\/ru.dict.itop-change-mgmt-itil.php","2.x\/itop-change-mgmt-itil\/pt_br.dict.itop-change-mgmt-itil.php"],"installed_version":"","available_version":"2.7.10","install":{"flag":1,"message":""}},"itop-change-mgmt":{"label":"Change Management","category":"business","dependencies":["itop-config-mgmt\/2.2.0","itop-tickets\/2.0.0"],"mandatory":false,"visible":true,"installer":"ChangeManagementInstaller","datamodel":["model.itop-change-mgmt.php"],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-change-mgmt","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-change-mgmt\/module.itop-change-mgmt.php","dictionary":["2.x\/itop-change-mgmt\/zh_cn.dict.itop-change-mgmt.php","2.x\/itop-change-mgmt\/en.dict.itop-change-mgmt.php","2.x\/itop-change-mgmt\/tr.dict.itop-change-mgmt.php","2.x\/itop-change-mgmt\/it.dict.itop-change-mgmt.php","2.x\/itop-change-mgmt\/cs.dict.itop-change-mgmt.php","2.x\/itop-change-mgmt\/hu.dict.itop-change-mgmt.php","2.x\/itop-change-mgmt\/ja.dict.itop-change-mgmt.php","2.x\/itop-change-mgmt\/da.dict.itop-change-mgmt.php","2.x\/itop-change-mgmt\/es_cr.dict.itop-change-mgmt.php","2.x\/itop-change-mgmt\/de.dict.itop-change-mgmt.php","2.x\/itop-change-mgmt\/nl.dict.itop-change-mgmt.php","2.x\/itop-change-mgmt\/sk.dict.itop-change-mgmt.php","2.x\/itop-change-mgmt\/ru.dict.itop-change-mgmt.php","2.x\/itop-change-mgmt\/pt_br.dict.itop-change-mgmt.php","2.x\/itop-change-mgmt\/fr.dict.itop-change-mgmt.php"],"installed_version":"","available_version":"2.7.10","install":{"flag":1,"message":""}},"itop-core-update":{"label":"iTop Core Update","category":"business","dependencies":["itop-files-information\/2.7.0","combodo-db-tools\/2.7.0"],"mandatory":false,"visible":true,"datamodel":["model.itop-core-update.php","src\/Service\/RunTimeEnvironmentCoreUpdater.php","src\/Service\/CoreUpdater.php","src\/Controller\/UpdateController.php","src\/Controller\/AjaxController.php"],"webservice":[],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-core-update","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-core-update\/module.itop-core-update.php","dictionary":["2.x\/itop-core-update\/ru.dict.itop-core-update.php","2.x\/itop-core-update\/de.dict.itop-core-update.php","2.x\/itop-core-update\/hu.dict.itop-core-update.php","2.x\/itop-core-update\/es_cr.dict.itop-core-update.php","2.x\/itop-core-update\/cs.dict.itop-core-update.php","2.x\/itop-core-update\/sk.dict.itop-core-update.php","2.x\/itop-core-update\/zh_cn.dict.itop-core-update.php","2.x\/itop-core-update\/fr.dict.itop-core-update.php","2.x\/itop-core-update\/da.dict.itop-core-update.php","2.x\/itop-core-update\/it.dict.itop-core-update.php","2.x\/itop-core-update\/pt_br.dict.itop-core-update.php","2.x\/itop-core-update\/en.dict.itop-core-update.php","2.x\/itop-core-update\/nl.dict.itop-core-update.php","2.x\/itop-core-update\/tr.dict.itop-core-update.php","2.x\/itop-core-update\/ja.dict.itop-core-update.php"],"installed_version":"","available_version":"2.7.10","install":{"flag":1,"message":""}},"itop-incident-mgmt-itil":{"label":"Incident Management ITIL","category":"business","dependencies":["itop-config-mgmt\/2.4.0","itop-tickets\/2.4.0","itop-profiles-itil\/2.3.0"],"mandatory":false,"visible":true,"datamodel":["model.itop-incident-mgmt-itil.php"],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-incident-mgmt-itil","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-incident-mgmt-itil\/module.itop-incident-mgmt-itil.php","dictionary":["2.x\/itop-incident-mgmt-itil\/da.dict.itop-incident-mgmt-itil.php","2.x\/itop-incident-mgmt-itil\/en.dict.itop-incident-mgmt-itil.php","2.x\/itop-incident-mgmt-itil\/de.dict.itop-incident-mgmt-itil.php","2.x\/itop-incident-mgmt-itil\/zh_cn.dict.itop-incident-mgmt-itil.php","2.x\/itop-incident-mgmt-itil\/sk.dict.itop-incident-mgmt-itil.php","2.x\/itop-incident-mgmt-itil\/fr.dict.itop-incident-mgmt-itil.php","2.x\/itop-incident-mgmt-itil\/hu.dict.itop-incident-mgmt-itil.php","2.x\/itop-incident-mgmt-itil\/ja.dict.itop-incident-mgmt-itil.php","2.x\/itop-incident-mgmt-itil\/cs.dict.itop-incident-mgmt-itil.php","2.x\/itop-incident-mgmt-itil\/nl.dict.itop-incident-mgmt-itil.php","2.x\/itop-incident-mgmt-itil\/ru.dict.itop-incident-mgmt-itil.php","2.x\/itop-incident-mgmt-itil\/tr.dict.itop-incident-mgmt-itil.php","2.x\/itop-incident-mgmt-itil\/it.dict.itop-incident-mgmt-itil.php","2.x\/itop-incident-mgmt-itil\/pt_br.dict.itop-incident-mgmt-itil.php","2.x\/itop-incident-mgmt-itil\/es_cr.dict.itop-incident-mgmt-itil.php"],"installed_version":"","available_version":"2.7.10","install":{"flag":1,"message":""}},"itop-knownerror-mgmt":{"label":"Known Errors Database","category":"business","dependencies":["itop-config-mgmt\/2.2.0","itop-tickets\/2.3.0"],"mandatory":false,"visible":true,"installer":"KnownErrorMgmtInstaller","datamodel":["model.itop-knownerror-mgmt.php"],"data.struct":[],"data.sample":["data.sample.faq-domains.xml"],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-knownerror-mgmt","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-knownerror-mgmt\/module.itop-knownerror-mgmt.php","dictionary":["2.x\/itop-knownerror-mgmt\/hu.dict.itop-knownerror-mgmt.php","2.x\/itop-knownerror-mgmt\/nl.dict.itop-knownerror-mgmt.php","2.x\/itop-knownerror-mgmt\/cs.dict.itop-knownerror-mgmt.php","2.x\/itop-knownerror-mgmt\/es_cr.dict.itop-knownerror-mgmt.php","2.x\/itop-knownerror-mgmt\/fr.dict.itop-knownerror-mgmt.php","2.x\/itop-knownerror-mgmt\/ru.dict.itop-knownerror-mgmt.php","2.x\/itop-knownerror-mgmt\/en.dict.itop-knownerror-mgmt.php","2.x\/itop-knownerror-mgmt\/da.dict.itop-knownerror-mgmt.php","2.x\/itop-knownerror-mgmt\/it.dict.itop-knownerror-mgmt.php","2.x\/itop-knownerror-mgmt\/sk.dict.itop-knownerror-mgmt.php","2.x\/itop-knownerror-mgmt\/pt_br.dict.itop-knownerror-mgmt.php","2.x\/itop-knownerror-mgmt\/tr.dict.itop-knownerror-mgmt.php","2.x\/itop-knownerror-mgmt\/zh_cn.dict.itop-knownerror-mgmt.php","2.x\/itop-knownerror-mgmt\/de.dict.itop-knownerror-mgmt.php","2.x\/itop-knownerror-mgmt\/ja.dict.itop-knownerror-mgmt.php"],"installed_version":"","available_version":"2.7.10","install":{"flag":1,"message":""}},"itop-oauth-client":{"label":"OAuth 2.0 client","category":"business","dependencies":["itop-welcome-itil\/2.7.7,"],"mandatory":false,"visible":true,"datamodel":["vendor\/autoload.php","model.itop-oauth-client.php","src\/Service\/PopupMenuExtension.php","src\/Service\/ApplicationUIExtension.php"],"webservice":[],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-oauth-client","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-oauth-client\/module.itop-oauth-client.php","dictionary":["2.x\/itop-oauth-client\/tr.dict.itop-oauth-client.php","2.x\/itop-oauth-client\/fr.dict.itop-oauth-client.php","2.x\/itop-oauth-client\/it.dict.itop-oauth-client.php","2.x\/itop-oauth-client\/en.dict.itop-oauth-client.php","2.x\/itop-oauth-client\/cs.dict.itop-oauth-client.php","2.x\/itop-oauth-client\/sk.dict.itop-oauth-client.php","2.x\/itop-oauth-client\/ru.dict.itop-oauth-client.php","2.x\/itop-oauth-client\/zh_cn.dict.itop-oauth-client.php","2.x\/itop-oauth-client\/pt_br.dict.itop-oauth-client.php","2.x\/itop-oauth-client\/es_cr.dict.itop-oauth-client.php","2.x\/itop-oauth-client\/nl.dict.itop-oauth-client.php","2.x\/itop-oauth-client\/ja.dict.itop-oauth-client.php","2.x\/itop-oauth-client\/de.dict.itop-oauth-client.php","2.x\/itop-oauth-client\/hu.dict.itop-oauth-client.php","2.x\/itop-oauth-client\/da.dict.itop-oauth-client.php"],"installed_version":"","available_version":"2.7.10","install":{"flag":1,"message":""}},"itop-problem-mgmt":{"label":"Problem Management","category":"business","dependencies":["itop-config-mgmt\/2.2.0","itop-tickets\/2.0.0"],"mandatory":false,"visible":true,"datamodel":["model.itop-problem-mgmt.php"],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-problem-mgmt","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-problem-mgmt\/module.itop-problem-mgmt.php","dictionary":["2.x\/itop-problem-mgmt\/tr.dict.itop-problem-mgmt.php","2.x\/itop-problem-mgmt\/cs.dict.itop-problem-mgmt.php","2.x\/itop-problem-mgmt\/sk.dict.itop-problem-mgmt.php","2.x\/itop-problem-mgmt\/pt_br.dict.itop-problem-mgmt.php","2.x\/itop-problem-mgmt\/es_cr.dict.itop-problem-mgmt.php","2.x\/itop-problem-mgmt\/da.dict.itop-problem-mgmt.php","2.x\/itop-problem-mgmt\/ru.dict.itop-problem-mgmt.php","2.x\/itop-problem-mgmt\/en.dict.itop-problem-mgmt.php","2.x\/itop-problem-mgmt\/hu.dict.itop-problem-mgmt.php","2.x\/itop-problem-mgmt\/fr.dict.itop-problem-mgmt.php","2.x\/itop-problem-mgmt\/nl.dict.itop-problem-mgmt.php","2.x\/itop-problem-mgmt\/ja.dict.itop-problem-mgmt.php","2.x\/itop-problem-mgmt\/de.dict.itop-problem-mgmt.php","2.x\/itop-problem-mgmt\/zh_cn.dict.itop-problem-mgmt.php","2.x\/itop-problem-mgmt\/it.dict.itop-problem-mgmt.php"],"installed_version":"","available_version":"2.7.10","install":{"flag":1,"message":""}},"itop-request-mgmt-itil":{"label":"User request Management ITIL","category":"business","dependencies":["itop-config-mgmt\/2.4.0","itop-tickets\/2.4.0"],"mandatory":false,"visible":true,"datamodel":["model.itop-request-mgmt-itil.php","main.itop-request-mgmt-itil.php"],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-request-mgmt-itil","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-request-mgmt-itil\/module.itop-request-mgmt-itil.php","dictionary":["2.x\/itop-request-mgmt-itil\/ja.dict.itop-request-mgmt-itil.php","2.x\/itop-request-mgmt-itil\/hu.dict.itop-request-mgmt-itil.php","2.x\/itop-request-mgmt-itil\/fr.dict.itop-request-mgmt-itil.php","2.x\/itop-request-mgmt-itil\/nl.dict.itop-request-mgmt-itil.php","2.x\/itop-request-mgmt-itil\/ru.dict.itop-request-mgmt-itil.php","2.x\/itop-request-mgmt-itil\/zh_cn.dict.itop-request-mgmt-itil.php","2.x\/itop-request-mgmt-itil\/it.dict.itop-request-mgmt-itil.php","2.x\/itop-request-mgmt-itil\/pt_br.dict.itop-request-mgmt-itil.php","2.x\/itop-request-mgmt-itil\/sk.dict.itop-request-mgmt-itil.php","2.x\/itop-request-mgmt-itil\/tr.dict.itop-request-mgmt-itil.php","2.x\/itop-request-mgmt-itil\/es_cr.dict.itop-request-mgmt-itil.php","2.x\/itop-request-mgmt-itil\/de.dict.itop-request-mgmt-itil.php","2.x\/itop-request-mgmt-itil\/en.dict.itop-request-mgmt-itil.php","2.x\/itop-request-mgmt-itil\/cs.dict.itop-request-mgmt-itil.php","2.x\/itop-request-mgmt-itil\/da.dict.itop-request-mgmt-itil.php"],"installed_version":"","available_version":"2.7.10","install":{"flag":1,"message":""}},"itop-request-mgmt":{"label":"Simple Ticket Management","category":"business","dependencies":["itop-config-mgmt\/2.4.0","itop-tickets\/2.4.0"],"mandatory":false,"visible":true,"datamodel":["model.itop-request-mgmt.php","main.itop-request-mgmt.php"],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-request-mgmt","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-request-mgmt\/module.itop-request-mgmt.php","dictionary":["2.x\/itop-request-mgmt\/tr.dict.itop-request-mgmt.php","2.x\/itop-request-mgmt\/da.dict.itop-request-mgmt.php","2.x\/itop-request-mgmt\/it.dict.itop-request-mgmt.php","2.x\/itop-request-mgmt\/fr.dict.itop-request-mgmt.php","2.x\/itop-request-mgmt\/ru.dict.itop-request-mgmt.php","2.x\/itop-request-mgmt\/cs.dict.itop-request-mgmt.php","2.x\/itop-request-mgmt\/hu.dict.itop-request-mgmt.php","2.x\/itop-request-mgmt\/en.dict.itop-request-mgmt.php","2.x\/itop-request-mgmt\/sk.dict.itop-request-mgmt.php","2.x\/itop-request-mgmt\/pt_br.dict.itop-request-mgmt.php","2.x\/itop-request-mgmt\/zh_cn.dict.itop-request-mgmt.php","2.x\/itop-request-mgmt\/de.dict.itop-request-mgmt.php","2.x\/itop-request-mgmt\/es_cr.dict.itop-request-mgmt.php","2.x\/itop-request-mgmt\/nl.dict.itop-request-mgmt.php","2.x\/itop-request-mgmt\/ja.dict.itop-request-mgmt.php"],"installed_version":"","available_version":"2.7.10","install":{"flag":1,"message":""}},"itop-service-mgmt-provider":{"label":"Service Management for Service Providers","category":"business","dependencies":["itop-config-mgmt\/2.2.0","itop-tickets\/2.0.0"],"mandatory":false,"visible":true,"installer":"ServiceMgmtProviderInstaller","datamodel":["model.itop-service-mgmt-provider.php"],"data.struct":[],"data.sample":["data.sample.organizations.xml","data.sample.contracts.xml","data.sample.servicefamilies.xml","data.sample.services.xml","data.sample.serviceelements.xml","data.sample.sla.xml","data.sample.slt.xml","data.sample.sltsla.xml","data.sample.contractservice.xml","data.sample.deliverymodelcontact.xml"],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-service-mgmt-provider","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-service-mgmt-provider\/module.itop-service-mgmt-provider.php","dictionary":["2.x\/itop-service-mgmt-provider\/zh_cn.dict.itop-service-mgmt-provider.php","2.x\/itop-service-mgmt-provider\/tr.dict.itop-service-mgmt-provider.php","2.x\/itop-service-mgmt-provider\/sk.dict.itop-service-mgmt-provider.php","2.x\/itop-service-mgmt-provider\/de.dict.itop-service-mgmt-provider.php","2.x\/itop-service-mgmt-provider\/ja.dict.itop-service-mgmt-provider.php","2.x\/itop-service-mgmt-provider\/ru.dict.itop-service-mgmt-provider.php","2.x\/itop-service-mgmt-provider\/fr.dict.itop-service-mgmt-provider.php","2.x\/itop-service-mgmt-provider\/hu.dict.itop-service-mgmt-provider.php","2.x\/itop-service-mgmt-provider\/en.dict.itop-service-mgmt-provider.php","2.x\/itop-service-mgmt-provider\/it.dict.itop-service-mgmt-provider.php","2.x\/itop-service-mgmt-provider\/cs.dict.itop-service-mgmt-provider.php","2.x\/itop-service-mgmt-provider\/es_cr.dict.itop-service-mgmt-provider.php","2.x\/itop-service-mgmt-provider\/pt_br.dict.itop-service-mgmt-provider.php","2.x\/itop-service-mgmt-provider\/da.dict.itop-service-mgmt-provider.php","2.x\/itop-service-mgmt-provider\/nl.dict.itop-service-mgmt-provider.php"],"installed_version":"","available_version":"2.7.10","install":{"flag":1,"message":""}},"itop-service-mgmt":{"label":"Service Management","category":"business","dependencies":["itop-config-mgmt\/2.2.0","itop-tickets\/2.0.0"],"mandatory":false,"visible":true,"installer":"ServiceMgmtInstaller","datamodel":["model.itop-service-mgmt.php"],"data.struct":[],"data.sample":["data.sample.organizations.xml","data.sample.contracts.xml","data.sample.servicefamilies.xml","data.sample.services.xml","data.sample.serviceelements.xml","data.sample.sla.xml","data.sample.slt.xml","data.sample.sltsla.xml","data.sample.contractservice.xml","data.sample.deliverymodelcontact.xml"],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-service-mgmt","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-service-mgmt\/module.itop-service-mgmt.php","dictionary":["2.x\/itop-service-mgmt\/hu.dict.itop-service-mgmt.php","2.x\/itop-service-mgmt\/es_cr.dict.itop-service-mgmt.php","2.x\/itop-service-mgmt\/nl.dict.itop-service-mgmt.php","2.x\/itop-service-mgmt\/sk.dict.itop-service-mgmt.php","2.x\/itop-service-mgmt\/it.dict.itop-service-mgmt.php","2.x\/itop-service-mgmt\/da.dict.itop-service-mgmt.php","2.x\/itop-service-mgmt\/zh_cn.dict.itop-service-mgmt.php","2.x\/itop-service-mgmt\/tr.dict.itop-service-mgmt.php","2.x\/itop-service-mgmt\/en.dict.itop-service-mgmt.php","2.x\/itop-service-mgmt\/cs.dict.itop-service-mgmt.php","2.x\/itop-service-mgmt\/de.dict.itop-service-mgmt.php","2.x\/itop-service-mgmt\/ja.dict.itop-service-mgmt.php","2.x\/itop-service-mgmt\/ru.dict.itop-service-mgmt.php","2.x\/itop-service-mgmt\/pt_br.dict.itop-service-mgmt.php","2.x\/itop-service-mgmt\/fr.dict.itop-service-mgmt.php"],"installed_version":"","available_version":"2.7.10","install":{"flag":1,"message":""}},"itop-full-itil":{"label":"Bridge - Request management ITIL + Incident management ITIL","category":"business","dependencies":["itop-request-mgmt-itil\/2.3.0","itop-incident-mgmt-itil\/2.3.0"],"mandatory":false,"visible":false,"auto_select":"SetupInfo::ModuleIsSelected(\"itop-request-mgmt-itil\") && SetupInfo::ModuleIsSelected(\"itop-incident-mgmt-itil\")","datamodel":[],"webservice":[],"data.struct":[],"data.sample":[],"doc.manual_setup":"","doc.more_information":"","settings":[],"itop_version":"1.0.2","root_dir":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-full-itil","module_file":"ROOTDIR_TOREPLACEdatamodels\/2.x\/itop-full-itil\/module.itop-full-itil.php","installed_version":"","available_version":"2.7.10","install":{"flag":1,"message":""}}} diff --git a/tests/php-unit-tests/unitary-tests/setup/unattended-install/resources/installation.xml b/tests/php-unit-tests/unitary-tests/setup/unattended-install/resources/installation.xml index b357dc7124..4a7c6bd004 100644 --- a/tests/php-unit-tests/unitary-tests/setup/unattended-install/resources/installation.xml +++ b/tests/php-unit-tests/unitary-tests/setup/unattended-install/resources/installation.xml @@ -205,7 +205,7 @@ itop-problem-mgmt Problem Management - Select this option track "Problems" in iTop. + Select this option to track "Problems" in iTop. itop-problem-mgmt