diff --git a/.doc/developers.md b/.doc/developers.md new file mode 100644 index 000000000..0ac5ce29e --- /dev/null +++ b/.doc/developers.md @@ -0,0 +1,9 @@ +# Developers + +## PHP Code Styles +We use `PHP CS Fixer` to ensure code formating consistency across PHP codebase. +You can find the configuration and instructions to run it [here](../tests/php-code-style/README.md). + +## PHP Static Analysis +We use `PHPStan` to ensure code quality and to detect potential bugs in our PHP codebase. +You can find the configuration and instructions to run it [here](../tests/php-static-analysis/README.md). \ No newline at end of file diff --git a/.github/workflows/action.yml b/.github/workflows/action.yml index 5e106ff9c..fdca1c0b9 100644 --- a/.github/workflows/action.yml +++ b/.github/workflows/action.yml @@ -26,13 +26,23 @@ jobs: fi - - name: Add internal tag if member + - name: Add internal tag if member of the organization if: env.is_member == 'true' run: | curl -X POST -H "Authorization: token ${{ secrets.PR_AUTOMATICALLY_ADD_TO_PROJECT }}" \ -H "Accept: application/vnd.github.v3+json" \ https://api.github.com/repos/Combodo/iTop/issues/${{ github.event.pull_request.number }}/labels \ -d '{"labels":["internal"]}' + + - name: Set PR author as assignee if member of the organization + if: env.is_member == 'true' + run: | + curl -L \ + -X POST \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer ${{ secrets.PR_AUTOMATICALLY_ADD_TO_PROJECT }}" \ + https://api.github.com/repos/Combodo/iTop/issues/${{ github.event.pull_request.number }}/assignees \ + -d '{"assignees":["${{ github.event.pull_request.user.login }}"]}' env: is_member: ${{ env.is_member }} @@ -40,4 +50,4 @@ jobs: uses: actions/add-to-project@v1.0.2 with: project-url: ${{ env.project_url }} - github-token: ${{ secrets.PR_AUTOMATICALLY_ADD_TO_PROJECT }} \ No newline at end of file + github-token: ${{ secrets.PR_AUTOMATICALLY_ADD_TO_PROJECT }} diff --git a/.gitignore b/.gitignore index df991db82..5ac6de748 100644 --- a/.gitignore +++ b/.gitignore @@ -58,6 +58,9 @@ tests/*/vendor/* /tests/php-unit-tests/phpunit.xml /tests/php-unit-tests/postbuild_integration.xml +# PHP CS Fixer: Cache file +/.php-cs-fixer.cache + # Jetbrains /.idea/** diff --git a/.phpstorm.meta.php b/.phpstorm.meta.php new file mode 100644 index 000000000..d7457b481 --- /dev/null +++ b/.phpstorm.meta.php @@ -0,0 +1,16 @@ + '@', + ])); + override(\MetaModel::GetObject(0), map([ + '' => '@', + ])); +} diff --git a/README.md b/README.md index 0b5651667..a6f98d02d 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,9 @@ iTop development is sponsored, led, and supported by [Combodo][0]. [0]: https://www.combodo.com +## Developers + +You can find information and instructions about our quality tools and how to run them [here](.doc/developers.md). ## Contributors diff --git a/application/cmdbabstract.class.inc.php b/application/cmdbabstract.class.inc.php index 49fa41663..8345cab30 100644 --- a/application/cmdbabstract.class.inc.php +++ b/application/cmdbabstract.class.inc.php @@ -5632,7 +5632,7 @@ JS * @return void * @since 3.1.0 */ - final public function AddAttributeFlags(string $sAttCode, int $iFlags, string $sTargetState = '', string $sReason = null): void + final public function AddAttributeFlags(string $sAttCode, int $iFlags, string $sTargetState = '', ?string $sReason = null): void { if (!isset($this->aAttributesFlags[$sTargetState])) { $this->aAttributesFlags[$sTargetState] = []; @@ -5655,7 +5655,7 @@ JS * @return void * @since 3.1.0 */ - final public function ForceAttributeFlags(string $sAttCode, int $iFlags, string $sTargetState = '', string $sReason = null): void + final public function ForceAttributeFlags(string $sAttCode, int $iFlags, string $sTargetState = '', ?string $sReason = null): void { if (!isset($this->aAttributesFlags[$sTargetState])) { $this->aAttributesFlags[$sTargetState] = []; @@ -5696,7 +5696,7 @@ JS * @return void * @since 3.1.0 */ - final public function AddInitialAttributeFlags(string $sAttCode, int $iFlags, string $sReason = null) + final public function AddInitialAttributeFlags(string $sAttCode, int $iFlags, ?string $sReason = null) { if (!isset($this->aInitialAttributesFlags)) { $this->aInitialAttributesFlags = []; @@ -5718,7 +5718,7 @@ JS * @return void * @since 3.1.0 */ - final public function ForceInitialAttributeFlags(string $sAttCode, int $iFlags, string $sReason = null) + final public function ForceInitialAttributeFlags(string $sAttCode, int $iFlags, ?string $sReason = null) { if (!isset($this->aInitialAttributesFlags)) { $this->aInitialAttributesFlags = []; diff --git a/application/dashboard.class.inc.php b/application/dashboard.class.inc.php index 115e4ff8b..a7ded14da 100644 --- a/application/dashboard.class.inc.php +++ b/application/dashboard.class.inc.php @@ -1029,7 +1029,7 @@ EOF var dashboard = $('.ibo-dashboard#$sDivId') dashboard.block(); $.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', - { operation: 'toggle_dashboard', dashboard_id: '$sId', file: '$sFile', extra_params: $sExtraParams, reload_url: '$sReloadURL' }, + { operation: 'toggle_dashboard', dashboard_id: '$sId', file: '$sFile', extra_params: $sExtraParams, reload_url: $sReloadURL }, function(data) { dashboard.html(data); dashboard.unblock(); diff --git a/application/datamodel.application.xml b/application/datamodel.application.xml index e20a1a95b..eb18e600f 100644 --- a/application/datamodel.application.xml +++ b/application/datamodel.application.xml @@ -1,10 +1,12 @@ - + cmdbAbstractObject - /* Resource access control abstraction. Can be herited by abstract resource access control classes. Generaly controlled using UR_ACTION_MODIFY access right. */ + /* Resource access control abstraction. Can be herited by abstract resource access control classes. Generally controlled using UR_ACTION_MODIFY access right. */ true @@ -552,7 +554,7 @@ Call $this->AddInitialAttributeFlags($sAttCode, $iFlags) for all the initial att - The login step result code (LoginWebPage::EXIT_CODE_...) + The login step result code (LoginWebPage::EXIT_CODE_...) integer @@ -849,5 +851,168 @@ Call $this->AddInitialAttributeFlags($sAttCode, $iFlags) for all the initial att + + + + Dashlet + + + + + + + + + + + + {{query.selected_class}} + + + + + + + + + + + + + + + + + + {{query.selected_class}} + + + + {{aggregation_function.value != 'count'}} + {{query.selected_class}} + numeric + + + + + + + + + + + + + + + {{order_by.value = 'function'}} + + + + + + + + + + + + + + + + + Dashlet + + + + + bizmodel + + + + + + Dashlet + + + + + + + + + + + + + + + + + + {{query.selected_class}} + enum + + + + + + {{query.selected_class}} + {{group_by.attribute}} + + + + + + + Dashlet + + + + + + + + + + + + + Dashlet + + + + + + + + + + + + + + true + + + + false + + + + + + + Dashlet + + + + + + + + + diff --git a/application/exceptions/ForgotPasswordApplicationException.php b/application/exceptions/ForgotPasswordApplicationException.php new file mode 100644 index 000000000..a6c27f4e2 --- /dev/null +++ b/application/exceptions/ForgotPasswordApplicationException.php @@ -0,0 +1,10 @@ +Get('app_icon_url'); $sDisplayIcon = Branding::GetLoginLogoAbsoluteUrl(); $aVars = [ 'sAppRootUrl' => utils::GetAbsoluteUrlAppRoot(), 'aPluginFormData' => $this->GetPluginFormData(), - 'sItopVersion' => ITOP_VERSION, - 'sVersionShort' => $sVersionShort, 'sIconUrl' => $sIconUrl, 'sDisplayIcon' => $sDisplayIcon, ]; diff --git a/application/loginwebpage.class.inc.php b/application/loginwebpage.class.inc.php index d5cf26b31..2355ff847 100644 --- a/application/loginwebpage.class.inc.php +++ b/application/loginwebpage.class.inc.php @@ -221,15 +221,15 @@ class LoginWebPage extends NiceWebPage if ($oUser != null) { if (!MetaModel::IsValidAttCode(get_class($oUser), 'reset_pwd_token')) { - throw new Exception(Dict::S('UI:ResetPwd-Error-NotPossible')); + throw new ForgotPasswordUserInputException('External accounts do not allow password reset'); } if (!$oUser->CanChangePassword()) { - throw new Exception(Dict::S('UI:ResetPwd-Error-FixedPwd')); + throw new ForgotPasswordUserInputException('The account does not allow password reset'); } $sTo = $oUser->GetResetPasswordEmail(); // throws Exceptions if not allowed if ($sTo == '') { - throw new Exception(Dict::S('UI:ResetPwd-Error-NoEmail')); + throw new ForgotPasswordUserInputException('Missing email address for this account'); } // This token allows the user to change the password without knowing the previous one @@ -255,17 +255,21 @@ class LoginWebPage extends NiceWebPage case EMAIL_SEND_ERROR: default: - IssueLog::Error('Failed to send the email with the NEW password for '.$oUser->Get('friendlyname').': '.implode(', ', $aIssues)); - throw new Exception(Dict::S('UI:ResetPwd-Error-Send')); + throw new ForgotPasswordApplicationException('Failed to send the password reset email for '.$oUser->Get('friendlyname').': '.implode(', ', $aIssues)); } } - $oTwigContext = new LoginTwigRenderer(); - $aVars = $oTwigContext->GetDefaultVars(); - $oTwigContext->Render($this, 'forgotpwdsent.html.twig', $aVars); - } catch (Exception $e) { - $this->DisplayForgotPwdForm(true, $e->getMessage()); + } catch (ForgotPasswordApplicationException $e) { + IssueLog::Error('Failed to process the forgot password request for user "'.$sAuthUser.'" [reason='.get_class($e).']: '.$e->getMessage()); + } catch (ForgotPasswordUserInputException $e) { + IssueLog::Info('Failed to process the forgot password request for user "'.$sAuthUser.'" [reason='.get_class($e).']: '.$e->getMessage()); + } catch (\Throwable $e) { + IssueLog::Error('Unexpected error while processing the forgot password request for user "'.$sAuthUser.'": '.$e->getMessage()); } + + $oTwigContext = new LoginTwigRenderer(); + $aVars = $oTwigContext->GetDefaultVars(); + $oTwigContext->Render($this, 'forgotpwdsent.html.twig', $aVars); } public function DisplayResetPwdForm($sErrorMessage = null) diff --git a/application/newsroomprovider.class.inc.php b/application/newsroomprovider.class.inc.php index dcdbf8b54..0b6a1d2ce 100644 --- a/application/newsroomprovider.class.inc.php +++ b/application/newsroomprovider.class.inc.php @@ -34,7 +34,7 @@ interface iNewsroomProvider * @param User $oUser The user for who to check if the provider is applicable. * return bool */ - public function IsApplicable(User $oUser = null); + public function IsApplicable(?User $oUser = null); /** * The human readable (localized) label for this provider @@ -139,7 +139,7 @@ abstract class NewsroomProviderBase implements iNewsroomProvider */ abstract public function GetViewAllURL(); - public function IsApplicable(User $oUser = null) + public function IsApplicable(?User $oUser = null) { return false; } diff --git a/application/query.class.inc.php b/application/query.class.inc.php index 21554480f..fee804482 100644 --- a/application/query.class.inc.php +++ b/application/query.class.inc.php @@ -151,7 +151,7 @@ abstract class Query extends cmdbAbstractObject * @return string|null * @since 3.1.0 */ - abstract public function GetExportUrl(array $aValues = null): ?string; + abstract public function GetExportUrl(?array $aValues = null): ?string; /** * Update last export information. @@ -227,7 +227,7 @@ class QueryOQL extends Query } /** @inheritdoc */ - public function GetExportUrl(array $aValues = null): ?string + public function GetExportUrl(?array $aValues = null): ?string { try { // retrieve attributes diff --git a/application/themehandler.class.inc.php b/application/themehandler.class.inc.php index 436417ccb..ada5819ba 100644 --- a/application/themehandler.class.inc.php +++ b/application/themehandler.class.inc.php @@ -967,7 +967,9 @@ CSS; } } } - array_map(function ($sVariableValue) { return ltrim($sVariableValue); }, $aVariablesResults); + array_map(function ($sVariableValue) { + return ltrim($sVariableValue); + }, $aVariablesResults); return $aVariablesResults; } diff --git a/application/utils.inc.php b/application/utils.inc.php index ea226e995..6708578cc 100644 --- a/application/utils.inc.php +++ b/application/utils.inc.php @@ -181,6 +181,9 @@ class utils protected static function LoadParamFile($sParamFile) { + if (utils::RealPath($sParamFile, APPROOT) !== false) { + throw new Exception("File '".utils::HtmlEntities($sParamFile)."' should be outside iTop"); + } if (!file_exists($sParamFile)) { throw new Exception("Could not find the parameter file: '".utils::HtmlEntities($sParamFile)."'"); } @@ -1284,7 +1287,7 @@ class utils * @throws \CoreException * @throws \Exception */ - public static function ExecITopScript(string $sScriptName, array $aArguments, string $sAuthUser = null, string $sAuthPwd = null) + public static function ExecITopScript(string $sScriptName, array $aArguments, ?string $sAuthUser = null, ?string $sAuthPwd = null) { $aDisabled = explode(', ', ini_get('disable_functions')); if (in_array('exec', $aDisabled)) { @@ -1374,7 +1377,7 @@ class utils * @return string A path to a folder into which any module can store cache data * The corresponding folder is created or cleaned upon code compilation */ - public static function GetCachePath(string $sEnvironment = null): string + public static function GetCachePath(?string $sEnvironment = null): string { if (is_null($sEnvironment)) { $sEnvironment = MetaModel::GetEnvironment(); @@ -1900,6 +1903,12 @@ SQL; return $response; } + public static function QuoteForPHP(string $sValue): string + { + $sEscaped = str_replace(['\\', "'"], ['\\\\', "\\'"], $sValue); + return "'$sEscaped'"; + } + /** * Get a standard list of character sets * @@ -2075,7 +2084,9 @@ SQL; } // Remove any remaining nulls (for positions that weren't referenced) - $aReplacements = array_filter($aReplacements, static function ($val) { return $val !== null; }); + $aReplacements = array_filter($aReplacements, static function ($val) { + return $val !== null; + }); } else { // For non-positional, we need to map each position $aReplacements = []; diff --git a/composer.json b/composer.json index fba023a2f..720359f78 100644 --- a/composer.json +++ b/composer.json @@ -4,7 +4,7 @@ "type": "project", "license": "AGPL-3.0-only", "require": { - "php": ">=8.1.0 <8.4.0", + "php": ">=8.1.0 <8.5.0", "ext-ctype": "*", "ext-dom": "*", "ext-gd": "*", @@ -12,8 +12,7 @@ "ext-json": "*", "ext-mysqli": "*", "ext-soap": "*", - "apereo/phpcas": "~1.6.0", - "firebase/php-jwt": "^6.4.0", + "apereo/phpcas": "dev-master", "guzzlehttp/guzzle": "^7.5.1", "league/oauth2-google": "^4.0.1", "nikic/php-parser": "dev-master", @@ -31,6 +30,7 @@ "symfony/mailer": "^6.4", "symfony/security-csrf": "^6.4", "symfony/twig-bundle": "~6.4.0", + "symfony/validator" : "^6.4", "symfony/yaml": "~6.4.0", "tecnickcom/tcpdf": "^6.6.0", "thenetworg/oauth2-azure": "^2.0" @@ -39,10 +39,16 @@ "symfony/stopwatch": "~6.4.0", "symfony/web-profiler-bundle": "~6.4.0" }, - "repositories": [{ - "type": "vcs", - "url": "https://github.com/Combodo/PHP-Parser" - }], + "repositories": [ + { + "type": "vcs", + "url": "https://github.com/Combodo/PHP-Parser" + }, + { + "type": "vcs", + "url": "https://github.com/EsupPortail/phpCAS" + } + ], "suggest": { "ext-libsodium": "Required to use the AttributeEncryptedString.", "ext-openssl": "Can be used as a polyfill if libsodium is not installed", diff --git a/composer.lock b/composer.lock index 6262f6cf6..07b88c2a1 100644 --- a/composer.lock +++ b/composer.lock @@ -4,20 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "26fa7aa920057d080bcc0948bf052fda", + "content-hash": "fc0e9e9dea11dcbb6272414776c30685", "packages": [ { "name": "apereo/phpcas", - "version": "1.6.1", + "version": "dev-master", "source": { "type": "git", - "url": "https://github.com/apereo/phpCAS.git", - "reference": "c129708154852656aabb13d8606cd5b12dbbabac" + "url": "https://github.com/EsupPortail/phpCAS.git", + "reference": "57a7744146a963d8fa80192e0ab351051b711ff6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/apereo/phpCAS/zipball/c129708154852656aabb13d8606cd5b12dbbabac", - "reference": "c129708154852656aabb13d8606cd5b12dbbabac", + "url": "https://api.github.com/repos/EsupPortail/phpCAS/zipball/57a7744146a963d8fa80192e0ab351051b711ff6", + "reference": "57a7744146a963d8fa80192e0ab351051b711ff6", "shasum": "" }, "require": { @@ -31,6 +31,7 @@ "phpstan/phpstan": "^1.5", "phpunit/phpunit": ">=7.5" }, + "default-branch": true, "type": "library", "extra": { "branch-alias": { @@ -45,15 +46,27 @@ "source/" ] }, - "notification-url": "https://packagist.org/downloads/", + "autoload-dev": { + "psr-4": { + "PhpCas\\": "test/CAS/" + } + }, + "scripts": { + "test": [ + "phpunit" + ], + "phpstan": [ + "phpstan" + ] + }, "license": [ "Apache-2.0" ], "authors": [ { "name": "Joachim Fritschi", - "email": "jfritschi@freenet.de", - "homepage": "https://github.com/jfritschi" + "homepage": "https://github.com/jfritschi", + "email": "jfritschi@freenet.de" }, { "name": "Adam Franco", @@ -72,10 +85,10 @@ "jasig" ], "support": { - "issues": "https://github.com/apereo/phpCAS/issues", - "source": "https://github.com/apereo/phpCAS/tree/1.6.1" + "source": "https://github.com/EsupPortail/phpCAS/tree/master", + "issues": "https://github.com/EsupPortail/phpCAS/issues" }, - "time": "2023-02-19T19:52:35+00:00" + "time": "2025-12-02T11:38:23+00:00" }, { "name": "doctrine/lexer", @@ -223,16 +236,16 @@ }, { "name": "firebase/php-jwt", - "version": "v6.11.1", + "version": "v7.0.3", "source": { "type": "git", "url": "https://github.com/firebase/php-jwt.git", - "reference": "d1e91ecf8c598d073d0995afa8cd5c75c6e19e66" + "reference": "28aa0694bcfdfa5e2959c394d5a1ee7a5083629e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/firebase/php-jwt/zipball/d1e91ecf8c598d073d0995afa8cd5c75c6e19e66", - "reference": "d1e91ecf8c598d073d0995afa8cd5c75c6e19e66", + "url": "https://api.github.com/repos/firebase/php-jwt/zipball/28aa0694bcfdfa5e2959c394d5a1ee7a5083629e", + "reference": "28aa0694bcfdfa5e2959c394d5a1ee7a5083629e", "shasum": "" }, "require": { @@ -280,9 +293,9 @@ ], "support": { "issues": "https://github.com/firebase/php-jwt/issues", - "source": "https://github.com/firebase/php-jwt/tree/v6.11.1" + "source": "https://github.com/firebase/php-jwt/tree/v7.0.3" }, - "time": "2025-04-09T20:32:01+00:00" + "time": "2026-02-25T22:16:40+00:00" }, { "name": "guzzlehttp/guzzle", @@ -611,22 +624,22 @@ }, { "name": "league/oauth2-client", - "version": "2.8.1", + "version": "2.9.0", "source": { "type": "git", "url": "https://github.com/thephpleague/oauth2-client.git", - "reference": "9df2924ca644736c835fc60466a3a60390d334f9" + "reference": "26e8c5da4f3d78cede7021e09b1330a0fc093d5e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/oauth2-client/zipball/9df2924ca644736c835fc60466a3a60390d334f9", - "reference": "9df2924ca644736c835fc60466a3a60390d334f9", + "url": "https://api.github.com/repos/thephpleague/oauth2-client/zipball/26e8c5da4f3d78cede7021e09b1330a0fc093d5e", + "reference": "26e8c5da4f3d78cede7021e09b1330a0fc093d5e", "shasum": "" }, "require": { "ext-json": "*", "guzzlehttp/guzzle": "^6.5.8 || ^7.4.5", - "php": "^7.1 || >=8.0.0 <8.5.0" + "php": "^7.1 || >=8.0.0 <8.6.0" }, "require-dev": { "mockery/mockery": "^1.3.5", @@ -670,22 +683,22 @@ ], "support": { "issues": "https://github.com/thephpleague/oauth2-client/issues", - "source": "https://github.com/thephpleague/oauth2-client/tree/2.8.1" + "source": "https://github.com/thephpleague/oauth2-client/tree/2.9.0" }, - "time": "2025-02-26T04:37:30+00:00" + "time": "2025-11-25T22:17:17+00:00" }, { "name": "league/oauth2-google", - "version": "4.0.1", + "version": "4.1.0", "source": { "type": "git", "url": "https://github.com/thephpleague/oauth2-google.git", - "reference": "1b01ba18ba31b29e88771e3e0979e5c91d4afe76" + "reference": "8b9bb43740ac6d994aca881a35f7bacbe98c0ffb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/oauth2-google/zipball/1b01ba18ba31b29e88771e3e0979e5c91d4afe76", - "reference": "1b01ba18ba31b29e88771e3e0979e5c91d4afe76", + "url": "https://api.github.com/repos/thephpleague/oauth2-google/zipball/8b9bb43740ac6d994aca881a35f7bacbe98c0ffb", + "reference": "8b9bb43740ac6d994aca881a35f7bacbe98c0ffb", "shasum": "" }, "require": { @@ -725,9 +738,9 @@ ], "support": { "issues": "https://github.com/thephpleague/oauth2-google/issues", - "source": "https://github.com/thephpleague/oauth2-google/tree/4.0.1" + "source": "https://github.com/thephpleague/oauth2-google/tree/4.1.0" }, - "time": "2023-03-17T15:20:52+00:00" + "time": "2025-12-15T12:24:14+00:00" }, { "name": "nikic/php-parser", @@ -735,12 +748,12 @@ "source": { "type": "git", "url": "https://github.com/Combodo/PHP-Parser.git", - "reference": "8ffc1239ff48ed2476b2672dbcc939fcdc5b0f7a" + "reference": "b2cd0735eb27788d5d41fa3c2cfaa01a593fd7fb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Combodo/PHP-Parser/zipball/8ffc1239ff48ed2476b2672dbcc939fcdc5b0f7a", - "reference": "8ffc1239ff48ed2476b2672dbcc939fcdc5b0f7a", + "url": "https://api.github.com/repos/Combodo/PHP-Parser/zipball/b2cd0735eb27788d5d41fa3c2cfaa01a593fd7fb", + "reference": "b2cd0735eb27788d5d41fa3c2cfaa01a593fd7fb", "shasum": "" }, "require": { @@ -789,7 +802,7 @@ "support": { "source": "https://github.com/Combodo/PHP-Parser/tree/master" }, - "time": "2025-09-09T09:14:16+00:00" + "time": "2025-09-18T12:29:15+00:00" }, { "name": "pear/archive_tar", @@ -924,16 +937,16 @@ }, { "name": "pear/pear-core-minimal", - "version": "v1.10.16", + "version": "v1.10.18", "source": { "type": "git", "url": "https://github.com/pear/pear-core-minimal.git", - "reference": "c0f51b45f50683bf5bbf558036854ebc9b54d033" + "reference": "c7b55789d01de0ce090d289b73f1bbd6a2f113b1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pear/pear-core-minimal/zipball/c0f51b45f50683bf5bbf558036854ebc9b54d033", - "reference": "c0f51b45f50683bf5bbf558036854ebc9b54d033", + "url": "https://api.github.com/repos/pear/pear-core-minimal/zipball/c7b55789d01de0ce090d289b73f1bbd6a2f113b1", + "reference": "c7b55789d01de0ce090d289b73f1bbd6a2f113b1", "shasum": "" }, "require": { @@ -969,7 +982,7 @@ "issues": "http://pear.php.net/bugs/search.php?cmd=display&package_name[]=PEAR", "source": "https://github.com/pear/pear-core-minimal" }, - "time": "2024-11-24T22:27:58+00:00" + "time": "2025-12-14T20:37:07+00:00" }, { "name": "pear/pear_exception", @@ -1721,16 +1734,16 @@ }, { "name": "symfony/cache", - "version": "v6.4.24", + "version": "v6.4.34", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "d038cd3054aeaf1c674022a77048b2ef6376a175" + "reference": "a0a1690543329685c044362c873b78c6de9d4faa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/d038cd3054aeaf1c674022a77048b2ef6376a175", - "reference": "d038cd3054aeaf1c674022a77048b2ef6376a175", + "url": "https://api.github.com/repos/symfony/cache/zipball/a0a1690543329685c044362c873b78c6de9d4faa", + "reference": "a0a1690543329685c044362c873b78c6de9d4faa", "shasum": "" }, "require": { @@ -1797,7 +1810,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v6.4.24" + "source": "https://github.com/symfony/cache/tree/v6.4.34" }, "funding": [ { @@ -1817,7 +1830,7 @@ "type": "tidelift" } ], - "time": "2025-07-30T09:32:03+00:00" + "time": "2026-02-20T15:06:30+00:00" }, { "name": "symfony/cache-contracts", @@ -1897,16 +1910,16 @@ }, { "name": "symfony/config", - "version": "v6.4.24", + "version": "v6.4.34", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "80e2cf005cf17138c97193be0434cdcfd1b2212e" + "reference": "ce9cb0c0d281aaf188b802d4968e42bfb60701e9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/80e2cf005cf17138c97193be0434cdcfd1b2212e", - "reference": "80e2cf005cf17138c97193be0434cdcfd1b2212e", + "url": "https://api.github.com/repos/symfony/config/zipball/ce9cb0c0d281aaf188b802d4968e42bfb60701e9", + "reference": "ce9cb0c0d281aaf188b802d4968e42bfb60701e9", "shasum": "" }, "require": { @@ -1952,7 +1965,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v6.4.24" + "source": "https://github.com/symfony/config/tree/v6.4.34" }, "funding": [ { @@ -1972,20 +1985,20 @@ "type": "tidelift" } ], - "time": "2025-07-26T13:50:30+00:00" + "time": "2026-02-24T17:34:50+00:00" }, { "name": "symfony/console", - "version": "v6.4.25", + "version": "v6.4.34", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "273fd29ff30ba0a88ca5fb83f7cf1ab69306adae" + "reference": "7b1f1c37eff5910ddda2831345467e593a5120ad" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/273fd29ff30ba0a88ca5fb83f7cf1ab69306adae", - "reference": "273fd29ff30ba0a88ca5fb83f7cf1ab69306adae", + "url": "https://api.github.com/repos/symfony/console/zipball/7b1f1c37eff5910ddda2831345467e593a5120ad", + "reference": "7b1f1c37eff5910ddda2831345467e593a5120ad", "shasum": "" }, "require": { @@ -2050,7 +2063,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v6.4.25" + "source": "https://github.com/symfony/console/tree/v6.4.34" }, "funding": [ { @@ -2070,20 +2083,20 @@ "type": "tidelift" } ], - "time": "2025-08-22T10:21:53+00:00" + "time": "2026-02-23T15:42:15+00:00" }, { "name": "symfony/css-selector", - "version": "v6.4.24", + "version": "v6.4.34", "source": { "type": "git", "url": "https://github.com/symfony/css-selector.git", - "reference": "9b784413143701aa3c94ac1869a159a9e53e8761" + "reference": "b0314c186f1464de048cce58979ff1625ca88bbb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/css-selector/zipball/9b784413143701aa3c94ac1869a159a9e53e8761", - "reference": "9b784413143701aa3c94ac1869a159a9e53e8761", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/b0314c186f1464de048cce58979ff1625ca88bbb", + "reference": "b0314c186f1464de048cce58979ff1625ca88bbb", "shasum": "" }, "require": { @@ -2119,7 +2132,7 @@ "description": "Converts CSS selectors to XPath expressions", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/css-selector/tree/v6.4.24" + "source": "https://github.com/symfony/css-selector/tree/v6.4.34" }, "funding": [ { @@ -2139,20 +2152,20 @@ "type": "tidelift" } ], - "time": "2025-07-10T08:14:14+00:00" + "time": "2026-02-16T08:37:21+00:00" }, { "name": "symfony/dependency-injection", - "version": "v6.4.25", + "version": "v6.4.34", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "900da8a42eceeb4a13a0ec34caa7db49328daff3" + "reference": "91e49958b8a6092e48e4711894a1aeb1b151c62a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/900da8a42eceeb4a13a0ec34caa7db49328daff3", - "reference": "900da8a42eceeb4a13a0ec34caa7db49328daff3", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/91e49958b8a6092e48e4711894a1aeb1b151c62a", + "reference": "91e49958b8a6092e48e4711894a1aeb1b151c62a", "shasum": "" }, "require": { @@ -2204,7 +2217,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v6.4.25" + "source": "https://github.com/symfony/dependency-injection/tree/v6.4.34" }, "funding": [ { @@ -2224,7 +2237,7 @@ "type": "tidelift" } ], - "time": "2025-08-13T09:41:44+00:00" + "time": "2026-02-24T15:33:38+00:00" }, { "name": "symfony/deprecation-contracts", @@ -2295,16 +2308,16 @@ }, { "name": "symfony/dotenv", - "version": "v6.4.24", + "version": "v6.4.30", "source": { "type": "git", "url": "https://github.com/symfony/dotenv.git", - "reference": "234b6c602f12b00693f4b0d1054386fb30dfc8ff" + "reference": "924edbc9631b75302def0258ed1697948b17baf6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dotenv/zipball/234b6c602f12b00693f4b0d1054386fb30dfc8ff", - "reference": "234b6c602f12b00693f4b0d1054386fb30dfc8ff", + "url": "https://api.github.com/repos/symfony/dotenv/zipball/924edbc9631b75302def0258ed1697948b17baf6", + "reference": "924edbc9631b75302def0258ed1697948b17baf6", "shasum": "" }, "require": { @@ -2349,7 +2362,7 @@ "environment" ], "support": { - "source": "https://github.com/symfony/dotenv/tree/v6.4.24" + "source": "https://github.com/symfony/dotenv/tree/v6.4.30" }, "funding": [ { @@ -2369,20 +2382,20 @@ "type": "tidelift" } ], - "time": "2025-07-10T08:14:14+00:00" + "time": "2025-11-14T17:33:48+00:00" }, { "name": "symfony/error-handler", - "version": "v6.4.24", + "version": "v6.4.32", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "30fd0b3cf0e972e82636038ce4db0e4fe777112c" + "reference": "8c18400784fcb014dc73c8d5601a9576af7f8ad4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/30fd0b3cf0e972e82636038ce4db0e4fe777112c", - "reference": "30fd0b3cf0e972e82636038ce4db0e4fe777112c", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/8c18400784fcb014dc73c8d5601a9576af7f8ad4", + "reference": "8c18400784fcb014dc73c8d5601a9576af7f8ad4", "shasum": "" }, "require": { @@ -2428,7 +2441,7 @@ "description": "Provides tools to manage errors and ease debugging PHP code", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/error-handler/tree/v6.4.24" + "source": "https://github.com/symfony/error-handler/tree/v6.4.32" }, "funding": [ { @@ -2448,20 +2461,20 @@ "type": "tidelift" } ], - "time": "2025-07-24T08:25:04+00:00" + "time": "2026-01-19T19:28:19+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v6.4.25", + "version": "v6.4.32", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "b0cf3162020603587363f0551cd3be43958611ff" + "reference": "99d7e101826e6610606b9433248f80c1997cd20b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b0cf3162020603587363f0551cd3be43958611ff", - "reference": "b0cf3162020603587363f0551cd3be43958611ff", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/99d7e101826e6610606b9433248f80c1997cd20b", + "reference": "99d7e101826e6610606b9433248f80c1997cd20b", "shasum": "" }, "require": { @@ -2512,7 +2525,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v6.4.25" + "source": "https://github.com/symfony/event-dispatcher/tree/v6.4.32" }, "funding": [ { @@ -2532,7 +2545,7 @@ "type": "tidelift" } ], - "time": "2025-08-13T09:41:44+00:00" + "time": "2026-01-05T11:13:48+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -2612,16 +2625,16 @@ }, { "name": "symfony/filesystem", - "version": "v6.4.24", + "version": "v6.4.34", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "75ae2edb7cdcc0c53766c30b0a2512b8df574bd8" + "reference": "01ffe0411b842f93c571e5c391f289c3fdd498c3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/75ae2edb7cdcc0c53766c30b0a2512b8df574bd8", - "reference": "75ae2edb7cdcc0c53766c30b0a2512b8df574bd8", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/01ffe0411b842f93c571e5c391f289c3fdd498c3", + "reference": "01ffe0411b842f93c571e5c391f289c3fdd498c3", "shasum": "" }, "require": { @@ -2658,7 +2671,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v6.4.24" + "source": "https://github.com/symfony/filesystem/tree/v6.4.34" }, "funding": [ { @@ -2678,20 +2691,20 @@ "type": "tidelift" } ], - "time": "2025-07-10T08:14:14+00:00" + "time": "2026-02-24T17:51:06+00:00" }, { "name": "symfony/finder", - "version": "v6.4.24", + "version": "v6.4.34", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "73089124388c8510efb8d2d1689285d285937b08" + "reference": "9590e86be1d1c57bfbb16d0dd040345378c20896" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/73089124388c8510efb8d2d1689285d285937b08", - "reference": "73089124388c8510efb8d2d1689285d285937b08", + "url": "https://api.github.com/repos/symfony/finder/zipball/9590e86be1d1c57bfbb16d0dd040345378c20896", + "reference": "9590e86be1d1c57bfbb16d0dd040345378c20896", "shasum": "" }, "require": { @@ -2726,7 +2739,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/finder/tree/v6.4.24" + "source": "https://github.com/symfony/finder/tree/v6.4.34" }, "funding": [ { @@ -2746,20 +2759,20 @@ "type": "tidelift" } ], - "time": "2025-07-15T12:02:45+00:00" + "time": "2026-01-28T15:16:37+00:00" }, { "name": "symfony/form", - "version": "v6.4.26", + "version": "v6.4.34", "source": { "type": "git", "url": "https://github.com/symfony/form.git", - "reference": "b40cdbe70be9274ea807ef61da7d0f8d1c70dc51" + "reference": "ed9275a133809bb48d949ba6dfdc808a819ebea2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/form/zipball/b40cdbe70be9274ea807ef61da7d0f8d1c70dc51", - "reference": "b40cdbe70be9274ea807ef61da7d0f8d1c70dc51", + "url": "https://api.github.com/repos/symfony/form/zipball/ed9275a133809bb48d949ba6dfdc808a819ebea2", + "reference": "ed9275a133809bb48d949ba6dfdc808a819ebea2", "shasum": "" }, "require": { @@ -2827,7 +2840,7 @@ "description": "Allows to easily create, process and reuse HTML forms", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/form/tree/v6.4.26" + "source": "https://github.com/symfony/form/tree/v6.4.34" }, "funding": [ { @@ -2847,20 +2860,20 @@ "type": "tidelift" } ], - "time": "2025-09-20T07:40:41+00:00" + "time": "2026-02-23T17:59:52+00:00" }, { "name": "symfony/framework-bundle", - "version": "v6.4.25", + "version": "v6.4.34", "source": { "type": "git", "url": "https://github.com/symfony/framework-bundle.git", - "reference": "1d6a764b58e4f780df00f71c20ba3a61095ea447" + "reference": "5b5d19473f22d699811a41b01cef2462bc42b238" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/1d6a764b58e4f780df00f71c20ba3a61095ea447", - "reference": "1d6a764b58e4f780df00f71c20ba3a61095ea447", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/5b5d19473f22d699811a41b01cef2462bc42b238", + "reference": "5b5d19473f22d699811a41b01cef2462bc42b238", "shasum": "" }, "require": { @@ -2980,7 +2993,7 @@ "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/framework-bundle/tree/v6.4.25" + "source": "https://github.com/symfony/framework-bundle/tree/v6.4.34" }, "funding": [ { @@ -3000,20 +3013,20 @@ "type": "tidelift" } ], - "time": "2025-08-26T10:44:20+00:00" + "time": "2026-02-24T16:00:52+00:00" }, { "name": "symfony/http-foundation", - "version": "v6.4.25", + "version": "v6.4.34", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "6bc974c0035b643aa497c58d46d9e25185e4b272" + "reference": "5bb346d1b4b2a616e5c3d99b3ee4d5810735c535" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/6bc974c0035b643aa497c58d46d9e25185e4b272", - "reference": "6bc974c0035b643aa497c58d46d9e25185e4b272", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/5bb346d1b4b2a616e5c3d99b3ee4d5810735c535", + "reference": "5bb346d1b4b2a616e5c3d99b3ee4d5810735c535", "shasum": "" }, "require": { @@ -3061,7 +3074,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v6.4.25" + "source": "https://github.com/symfony/http-foundation/tree/v6.4.34" }, "funding": [ { @@ -3081,20 +3094,20 @@ "type": "tidelift" } ], - "time": "2025-08-20T06:48:20+00:00" + "time": "2026-02-21T15:48:41+00:00" }, { "name": "symfony/http-kernel", - "version": "v6.4.25", + "version": "v6.4.34", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "a0ee3cea5cabf4ed960fd2ef57668ceeacdb6e15" + "reference": "006a49fc4f41ee21a6ca61e69caed1c30b29f07c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/a0ee3cea5cabf4ed960fd2ef57668ceeacdb6e15", - "reference": "a0ee3cea5cabf4ed960fd2ef57668ceeacdb6e15", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/006a49fc4f41ee21a6ca61e69caed1c30b29f07c", + "reference": "006a49fc4f41ee21a6ca61e69caed1c30b29f07c", "shasum": "" }, "require": { @@ -3135,7 +3148,7 @@ "symfony/config": "^6.1|^7.0", "symfony/console": "^5.4|^6.0|^7.0", "symfony/css-selector": "^5.4|^6.0|^7.0", - "symfony/dependency-injection": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4.1|^7.0.1", "symfony/dom-crawler": "^5.4|^6.0|^7.0", "symfony/expression-language": "^5.4|^6.0|^7.0", "symfony/finder": "^5.4|^6.0|^7.0", @@ -3179,7 +3192,7 @@ "description": "Provides a structured process for converting a Request into a Response", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-kernel/tree/v6.4.25" + "source": "https://github.com/symfony/http-kernel/tree/v6.4.34" }, "funding": [ { @@ -3199,20 +3212,20 @@ "type": "tidelift" } ], - "time": "2025-08-29T07:55:45+00:00" + "time": "2026-02-26T08:27:11+00:00" }, { "name": "symfony/mailer", - "version": "v6.4.25", + "version": "v6.4.34", "source": { "type": "git", "url": "https://github.com/symfony/mailer.git", - "reference": "628b43b45a3e6b15c8a633fb22df547ed9b492a2" + "reference": "01b846f48e53ee4096692a383637a1fa4d577301" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailer/zipball/628b43b45a3e6b15c8a633fb22df547ed9b492a2", - "reference": "628b43b45a3e6b15c8a633fb22df547ed9b492a2", + "url": "https://api.github.com/repos/symfony/mailer/zipball/01b846f48e53ee4096692a383637a1fa4d577301", + "reference": "01b846f48e53ee4096692a383637a1fa4d577301", "shasum": "" }, "require": { @@ -3263,7 +3276,7 @@ "description": "Helps sending emails", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailer/tree/v6.4.25" + "source": "https://github.com/symfony/mailer/tree/v6.4.34" }, "funding": [ { @@ -3283,20 +3296,20 @@ "type": "tidelift" } ], - "time": "2025-08-13T09:41:44+00:00" + "time": "2026-02-24T09:34:36+00:00" }, { "name": "symfony/mime", - "version": "v6.4.24", + "version": "v6.4.34", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "664d5e844a2de5e11c8255d0aef6bc15a9660ac7" + "reference": "2b32fbbe10b36a8379efab6e702ad8b917151839" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/664d5e844a2de5e11c8255d0aef6bc15a9660ac7", - "reference": "664d5e844a2de5e11c8255d0aef6bc15a9660ac7", + "url": "https://api.github.com/repos/symfony/mime/zipball/2b32fbbe10b36a8379efab6e702ad8b917151839", + "reference": "2b32fbbe10b36a8379efab6e702ad8b917151839", "shasum": "" }, "require": { @@ -3352,7 +3365,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v6.4.24" + "source": "https://github.com/symfony/mime/tree/v6.4.34" }, "funding": [ { @@ -3372,20 +3385,20 @@ "type": "tidelift" } ], - "time": "2025-07-15T12:02:45+00:00" + "time": "2026-02-02T17:01:23+00:00" }, { "name": "symfony/options-resolver", - "version": "v6.4.25", + "version": "v6.4.30", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "d28e7e2db8a73e9511df892d36445f61314bbebe" + "reference": "eeaa8cabe54c7b3516938c72a4a161c0cc80a34f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/d28e7e2db8a73e9511df892d36445f61314bbebe", - "reference": "d28e7e2db8a73e9511df892d36445f61314bbebe", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/eeaa8cabe54c7b3516938c72a4a161c0cc80a34f", + "reference": "eeaa8cabe54c7b3516938c72a4a161c0cc80a34f", "shasum": "" }, "require": { @@ -3423,7 +3436,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v6.4.25" + "source": "https://github.com/symfony/options-resolver/tree/v6.4.30" }, "funding": [ { @@ -3443,20 +3456,20 @@ "type": "tidelift" } ], - "time": "2025-08-04T17:06:28+00:00" + "time": "2025-11-12T13:06:53+00:00" }, { "name": "symfony/password-hasher", - "version": "v6.4.24", + "version": "v6.4.32", "source": { "type": "git", "url": "https://github.com/symfony/password-hasher.git", - "reference": "dcab5ac87450aaed26483ba49c2ce86808da7557" + "reference": "fbdfa5a2ca218ec8bb9029517426df2d780bdba9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/password-hasher/zipball/dcab5ac87450aaed26483ba49c2ce86808da7557", - "reference": "dcab5ac87450aaed26483ba49c2ce86808da7557", + "url": "https://api.github.com/repos/symfony/password-hasher/zipball/fbdfa5a2ca218ec8bb9029517426df2d780bdba9", + "reference": "fbdfa5a2ca218ec8bb9029517426df2d780bdba9", "shasum": "" }, "require": { @@ -3499,7 +3512,7 @@ "password" ], "support": { - "source": "https://github.com/symfony/password-hasher/tree/v6.4.24" + "source": "https://github.com/symfony/password-hasher/tree/v6.4.32" }, "funding": [ { @@ -3519,7 +3532,7 @@ "type": "tidelift" } ], - "time": "2025-07-10T08:14:14+00:00" + "time": "2026-01-01T21:24:53+00:00" }, { "name": "symfony/polyfill-ctype", @@ -4113,22 +4126,22 @@ }, { "name": "symfony/property-access", - "version": "v6.4.25", + "version": "v6.4.32", "source": { "type": "git", "url": "https://github.com/symfony/property-access.git", - "reference": "fedc771326d4978a7d3167fa009a509b06a2e168" + "reference": "6dfa655ac9e9860c05cabb287f34da86b18c237e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-access/zipball/fedc771326d4978a7d3167fa009a509b06a2e168", - "reference": "fedc771326d4978a7d3167fa009a509b06a2e168", + "url": "https://api.github.com/repos/symfony/property-access/zipball/6dfa655ac9e9860c05cabb287f34da86b18c237e", + "reference": "6dfa655ac9e9860c05cabb287f34da86b18c237e", "shasum": "" }, "require": { "php": ">=8.1", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/property-info": "^5.4|^6.0|^7.0" + "symfony/property-info": "^6.4.32|~7.3.10|^7.4.4" }, "require-dev": { "symfony/cache": "^5.4|^6.0|^7.0" @@ -4170,7 +4183,7 @@ "reflection" ], "support": { - "source": "https://github.com/symfony/property-access/tree/v6.4.25" + "source": "https://github.com/symfony/property-access/tree/v6.4.32" }, "funding": [ { @@ -4190,20 +4203,20 @@ "type": "tidelift" } ], - "time": "2025-08-12T15:42:57+00:00" + "time": "2026-01-05T08:25:17+00:00" }, { "name": "symfony/property-info", - "version": "v6.4.24", + "version": "v6.4.34", "source": { "type": "git", "url": "https://github.com/symfony/property-info.git", - "reference": "1056ae3621eeddd78d7c5ec074f1c1784324eec6" + "reference": "916455e4c9dcddbebfd101f29d7983841c3564e0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/property-info/zipball/1056ae3621eeddd78d7c5ec074f1c1784324eec6", - "reference": "1056ae3621eeddd78d7c5ec074f1c1784324eec6", + "url": "https://api.github.com/repos/symfony/property-info/zipball/916455e4c9dcddbebfd101f29d7983841c3564e0", + "reference": "916455e4c9dcddbebfd101f29d7983841c3564e0", "shasum": "" }, "require": { @@ -4212,7 +4225,7 @@ }, "conflict": { "doctrine/annotations": "<1.12", - "phpdocumentor/reflection-docblock": "<5.2", + "phpdocumentor/reflection-docblock": "<5.2|>=6", "phpdocumentor/type-resolver": "<1.5.1", "symfony/cache": "<5.4", "symfony/dependency-injection": "<5.4|>=6.0,<6.4", @@ -4260,7 +4273,7 @@ "validator" ], "support": { - "source": "https://github.com/symfony/property-info/tree/v6.4.24" + "source": "https://github.com/symfony/property-info/tree/v6.4.34" }, "funding": [ { @@ -4280,20 +4293,20 @@ "type": "tidelift" } ], - "time": "2025-07-14T16:38:25+00:00" + "time": "2026-02-13T09:42:46+00:00" }, { "name": "symfony/routing", - "version": "v6.4.24", + "version": "v6.4.34", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "e4f94e625c8e6f910aa004a0042f7b2d398278f5" + "reference": "5ab3a3e1a03535ec5ca6ce2d39e4369a1096ae47" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/e4f94e625c8e6f910aa004a0042f7b2d398278f5", - "reference": "e4f94e625c8e6f910aa004a0042f7b2d398278f5", + "url": "https://api.github.com/repos/symfony/routing/zipball/5ab3a3e1a03535ec5ca6ce2d39e4369a1096ae47", + "reference": "5ab3a3e1a03535ec5ca6ce2d39e4369a1096ae47", "shasum": "" }, "require": { @@ -4347,7 +4360,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v6.4.24" + "source": "https://github.com/symfony/routing/tree/v6.4.34" }, "funding": [ { @@ -4367,20 +4380,20 @@ "type": "tidelift" } ], - "time": "2025-07-15T08:46:37+00:00" + "time": "2026-02-24T17:34:50+00:00" }, { "name": "symfony/security-core", - "version": "v6.4.26", + "version": "v6.4.31", "source": { "type": "git", "url": "https://github.com/symfony/security-core.git", - "reference": "8b7c95bf04d82fcd0c06a918b2d849bfb2ab9cc0" + "reference": "fa269ad61a021cc54329dc96e57bed78ba720bfe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-core/zipball/8b7c95bf04d82fcd0c06a918b2d849bfb2ab9cc0", - "reference": "8b7c95bf04d82fcd0c06a918b2d849bfb2ab9cc0", + "url": "https://api.github.com/repos/symfony/security-core/zipball/fa269ad61a021cc54329dc96e57bed78ba720bfe", + "reference": "fa269ad61a021cc54329dc96e57bed78ba720bfe", "shasum": "" }, "require": { @@ -4437,7 +4450,7 @@ "description": "Symfony Security Component - Core Library", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-core/tree/v6.4.26" + "source": "https://github.com/symfony/security-core/tree/v6.4.31" }, "funding": [ { @@ -4457,20 +4470,20 @@ "type": "tidelift" } ], - "time": "2025-09-02T19:15:26+00:00" + "time": "2025-12-17T22:32:13+00:00" }, { "name": "symfony/security-csrf", - "version": "v6.4.24", + "version": "v6.4.31", "source": { "type": "git", "url": "https://github.com/symfony/security-csrf.git", - "reference": "9a1efc8c10b86bcedc9233affd10c716b54ca1b7" + "reference": "52f62836fcb19cd351ef3a2aa9cf61a489e8990f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/security-csrf/zipball/9a1efc8c10b86bcedc9233affd10c716b54ca1b7", - "reference": "9a1efc8c10b86bcedc9233affd10c716b54ca1b7", + "url": "https://api.github.com/repos/symfony/security-csrf/zipball/52f62836fcb19cd351ef3a2aa9cf61a489e8990f", + "reference": "52f62836fcb19cd351ef3a2aa9cf61a489e8990f", "shasum": "" }, "require": { @@ -4509,7 +4522,7 @@ "description": "Symfony Security Component - CSRF Library", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/security-csrf/tree/v6.4.24" + "source": "https://github.com/symfony/security-csrf/tree/v6.4.31" }, "funding": [ { @@ -4529,20 +4542,20 @@ "type": "tidelift" } ], - "time": "2025-07-10T08:14:14+00:00" + "time": "2025-12-17T22:32:13+00:00" }, { "name": "symfony/service-contracts", - "version": "v3.6.0", + "version": "v3.6.1", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4" + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4", - "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43", + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43", "shasum": "" }, "require": { @@ -4596,7 +4609,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.6.0" + "source": "https://github.com/symfony/service-contracts/tree/v3.6.1" }, "funding": [ { @@ -4607,25 +4620,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-04-25T09:37:31+00:00" + "time": "2025-07-15T11:30:57+00:00" }, { "name": "symfony/string", - "version": "v6.4.25", + "version": "v6.4.34", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "7cdec7edfaf2cdd9c18901e35bcf9653d6209ff1" + "reference": "2adaf4106f2ef4c67271971bde6d3fe0a6936432" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/7cdec7edfaf2cdd9c18901e35bcf9653d6209ff1", - "reference": "7cdec7edfaf2cdd9c18901e35bcf9653d6209ff1", + "url": "https://api.github.com/repos/symfony/string/zipball/2adaf4106f2ef4c67271971bde6d3fe0a6936432", + "reference": "2adaf4106f2ef4c67271971bde6d3fe0a6936432", "shasum": "" }, "require": { @@ -4639,7 +4656,6 @@ "symfony/translation-contracts": "<2.5" }, "require-dev": { - "symfony/error-handler": "^5.4|^6.0|^7.0", "symfony/http-client": "^5.4|^6.0|^7.0", "symfony/intl": "^6.2|^7.0", "symfony/translation-contracts": "^2.5|^3.0", @@ -4682,7 +4698,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v6.4.25" + "source": "https://github.com/symfony/string/tree/v6.4.34" }, "funding": [ { @@ -4702,20 +4718,20 @@ "type": "tidelift" } ], - "time": "2025-08-22T12:33:20+00:00" + "time": "2026-02-08T20:44:54+00:00" }, { "name": "symfony/translation-contracts", - "version": "v3.6.0", + "version": "v3.6.1", "source": { "type": "git", "url": "https://github.com/symfony/translation-contracts.git", - "reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d" + "reference": "65a8bc82080447fae78373aa10f8d13b38338977" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/df210c7a2573f1913b2d17cc95f90f53a73d8f7d", - "reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/65a8bc82080447fae78373aa10f8d13b38338977", + "reference": "65a8bc82080447fae78373aa10f8d13b38338977", "shasum": "" }, "require": { @@ -4764,7 +4780,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/translation-contracts/tree/v3.6.0" + "source": "https://github.com/symfony/translation-contracts/tree/v3.6.1" }, "funding": [ { @@ -4775,25 +4791,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-27T08:32:26+00:00" + "time": "2025-07-15T13:41:35+00:00" }, { "name": "symfony/twig-bridge", - "version": "v6.4.25", + "version": "v6.4.34", "source": { "type": "git", "url": "https://github.com/symfony/twig-bridge.git", - "reference": "9d13e87591c9de3221c8d6f23cd9a2b5958607bf" + "reference": "5169074f4a88dfb02eeccddaba78edfdf212a9b2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/9d13e87591c9de3221c8d6f23cd9a2b5958607bf", - "reference": "9d13e87591c9de3221c8d6f23cd9a2b5958607bf", + "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/5169074f4a88dfb02eeccddaba78edfdf212a9b2", + "reference": "5169074f4a88dfb02eeccddaba78edfdf212a9b2", "shasum": "" }, "require": { @@ -4806,7 +4826,7 @@ "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<1.4.0", "symfony/console": "<5.4", - "symfony/form": "<6.3", + "symfony/form": "<6.4.32|>7,<7.3.10|>7.4,<7.4.4", "symfony/http-foundation": "<5.4", "symfony/http-kernel": "<6.4", "symfony/mime": "<6.2", @@ -4824,7 +4844,7 @@ "symfony/dependency-injection": "^5.4|^6.0|^7.0", "symfony/expression-language": "^5.4|^6.0|^7.0", "symfony/finder": "^5.4|^6.0|^7.0", - "symfony/form": "^6.4.20|^7.2.5", + "symfony/form": "^6.4.32|~7.3.10|^7.4.4", "symfony/html-sanitizer": "^6.1|^7.0", "symfony/http-foundation": "^5.4|^6.0|^7.0", "symfony/http-kernel": "^6.4|^7.0", @@ -4873,7 +4893,7 @@ "description": "Provides integration for Twig with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bridge/tree/v6.4.25" + "source": "https://github.com/symfony/twig-bridge/tree/v6.4.34" }, "funding": [ { @@ -4893,20 +4913,20 @@ "type": "tidelift" } ], - "time": "2025-08-13T09:41:44+00:00" + "time": "2026-02-23T18:17:33+00:00" }, { "name": "symfony/twig-bundle", - "version": "v6.4.24", + "version": "v6.4.32", "source": { "type": "git", "url": "https://github.com/symfony/twig-bundle.git", - "reference": "3b48b6e8225495c6d2438828982b4d219ca565ba" + "reference": "a5c8dcc11a5bf9c96320da20070d2e158a4e0b30" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/3b48b6e8225495c6d2438828982b4d219ca565ba", - "reference": "3b48b6e8225495c6d2438828982b4d219ca565ba", + "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/a5c8dcc11a5bf9c96320da20070d2e158a4e0b30", + "reference": "a5c8dcc11a5bf9c96320da20070d2e158a4e0b30", "shasum": "" }, "require": { @@ -4961,7 +4981,7 @@ "description": "Provides a tight integration of Twig into the Symfony full-stack framework", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bundle/tree/v6.4.24" + "source": "https://github.com/symfony/twig-bundle/tree/v6.4.32" }, "funding": [ { @@ -4981,20 +5001,121 @@ "type": "tidelift" } ], - "time": "2025-07-10T08:14:14+00:00" + "time": "2026-01-05T12:44:39+00:00" }, { - "name": "symfony/var-dumper", - "version": "v6.4.26", + "name": "symfony/validator", + "version": "v6.4.34", "source": { "type": "git", - "url": "https://github.com/symfony/var-dumper.git", - "reference": "cfae1497a2f1eaad78dbc0590311c599c7178d4a" + "url": "https://github.com/symfony/validator.git", + "reference": "7c3897b7f739d4ab913481e680405ca82d08084d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/cfae1497a2f1eaad78dbc0590311c599c7178d4a", - "reference": "cfae1497a2f1eaad78dbc0590311c599c7178d4a", + "url": "https://api.github.com/repos/symfony/validator/zipball/7c3897b7f739d4ab913481e680405ca82d08084d", + "reference": "7c3897b7f739d4ab913481e680405ca82d08084d", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php83": "^1.27", + "symfony/translation-contracts": "^2.5|^3" + }, + "conflict": { + "doctrine/annotations": "<1.13", + "doctrine/lexer": "<1.1", + "symfony/dependency-injection": "<5.4", + "symfony/expression-language": "<5.4", + "symfony/http-kernel": "<5.4", + "symfony/intl": "<5.4", + "symfony/property-info": "<5.4", + "symfony/translation": "<5.4.35|>=6.0,<6.3.12|>=6.4,<6.4.3|>=7.0,<7.0.3", + "symfony/yaml": "<5.4" + }, + "require-dev": { + "doctrine/annotations": "^1.13|^2", + "egulias/email-validator": "^2.1.10|^3|^4", + "symfony/cache": "^5.4|^6.0|^7.0", + "symfony/config": "^5.4|^6.0|^7.0", + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/finder": "^5.4|^6.0|^7.0", + "symfony/http-client": "^5.4|^6.0|^7.0", + "symfony/http-foundation": "^5.4|^6.0|^7.0", + "symfony/http-kernel": "^5.4|^6.0|^7.0", + "symfony/intl": "^5.4|^6.0|^7.0", + "symfony/mime": "^5.4|^6.0|^7.0", + "symfony/property-access": "^5.4|^6.0|^7.0", + "symfony/property-info": "^5.4|^6.0|^7.0", + "symfony/translation": "^5.4.35|~6.3.12|^6.4.3|^7.0.3", + "symfony/yaml": "^5.4|^6.0|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Validator\\": "" + }, + "exclude-from-classmap": [ + "/Tests/", + "/Resources/bin/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to validate values", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/validator/tree/v6.4.34" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2026-02-23T17:49:24+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v6.4.32", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "131fc9915e0343052af5ed5040401b481ca192aa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/131fc9915e0343052af5ed5040401b481ca192aa", + "reference": "131fc9915e0343052af5ed5040401b481ca192aa", "shasum": "" }, "require": { @@ -5049,7 +5170,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v6.4.26" + "source": "https://github.com/symfony/var-dumper/tree/v6.4.32" }, "funding": [ { @@ -5069,20 +5190,20 @@ "type": "tidelift" } ], - "time": "2025-09-25T15:37:27+00:00" + "time": "2026-01-01T13:34:06+00:00" }, { "name": "symfony/var-exporter", - "version": "v6.4.25", + "version": "v6.4.26", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "4ff50a1b7c75d1d596aca50899d0c8c7e3de8358" + "reference": "466fcac5fa2e871f83d31173f80e9c2684743bfc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/4ff50a1b7c75d1d596aca50899d0c8c7e3de8358", - "reference": "4ff50a1b7c75d1d596aca50899d0c8c7e3de8358", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/466fcac5fa2e871f83d31173f80e9c2684743bfc", + "reference": "466fcac5fa2e871f83d31173f80e9c2684743bfc", "shasum": "" }, "require": { @@ -5130,7 +5251,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v6.4.25" + "source": "https://github.com/symfony/var-exporter/tree/v6.4.26" }, "funding": [ { @@ -5150,20 +5271,20 @@ "type": "tidelift" } ], - "time": "2025-08-18T13:06:32+00:00" + "time": "2025-09-11T09:57:09+00:00" }, { "name": "symfony/yaml", - "version": "v6.4.25", + "version": "v6.4.34", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "e54b060bc9c3dc3d4258bf0d165d0064e755f565" + "reference": "7bca30dabed7900a08c5ad4f1d6483f881a64d0f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/e54b060bc9c3dc3d4258bf0d165d0064e755f565", - "reference": "e54b060bc9c3dc3d4258bf0d165d0064e755f565", + "url": "https://api.github.com/repos/symfony/yaml/zipball/7bca30dabed7900a08c5ad4f1d6483f881a64d0f", + "reference": "7bca30dabed7900a08c5ad4f1d6483f881a64d0f", "shasum": "" }, "require": { @@ -5206,7 +5327,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v6.4.25" + "source": "https://github.com/symfony/yaml/tree/v6.4.34" }, "funding": [ { @@ -5226,20 +5347,20 @@ "type": "tidelift" } ], - "time": "2025-08-26T16:59:00+00:00" + "time": "2026-02-06T18:32:11+00:00" }, { "name": "tecnickcom/tcpdf", - "version": "6.10.0", + "version": "6.11.0", "source": { "type": "git", "url": "https://github.com/tecnickcom/TCPDF.git", - "reference": "ca5b6de294512145db96bcbc94e61696599c391d" + "reference": "81172e58edb1cfae4019ef150ccbdc0e9a8c85c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/tecnickcom/TCPDF/zipball/ca5b6de294512145db96bcbc94e61696599c391d", - "reference": "ca5b6de294512145db96bcbc94e61696599c391d", + "url": "https://api.github.com/repos/tecnickcom/TCPDF/zipball/81172e58edb1cfae4019ef150ccbdc0e9a8c85c9", + "reference": "81172e58edb1cfae4019ef150ccbdc0e9a8c85c9", "shasum": "" }, "require": { @@ -5289,7 +5410,7 @@ ], "support": { "issues": "https://github.com/tecnickcom/TCPDF/issues", - "source": "https://github.com/tecnickcom/TCPDF/tree/6.10.0" + "source": "https://github.com/tecnickcom/TCPDF/tree/6.11.0" }, "funding": [ { @@ -5297,26 +5418,26 @@ "type": "custom" } ], - "time": "2025-05-27T18:02:28+00:00" + "time": "2026-03-01T09:35:25+00:00" }, { "name": "thenetworg/oauth2-azure", - "version": "v2.2.2", + "version": "v2.2.5", "source": { "type": "git", "url": "https://github.com/TheNetworg/oauth2-azure.git", - "reference": "be204a5135f016470a9c33e82ab48785bbc11af2" + "reference": "06f1aa023e18cc3ea80df6410c7c2dc5502a3655" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/TheNetworg/oauth2-azure/zipball/be204a5135f016470a9c33e82ab48785bbc11af2", - "reference": "be204a5135f016470a9c33e82ab48785bbc11af2", + "url": "https://api.github.com/repos/TheNetworg/oauth2-azure/zipball/06f1aa023e18cc3ea80df6410c7c2dc5502a3655", + "reference": "06f1aa023e18cc3ea80df6410c7c2dc5502a3655", "shasum": "" }, "require": { "ext-json": "*", "ext-openssl": "*", - "firebase/php-jwt": "~3.0||~4.0||~5.0||~6.0", + "firebase/php-jwt": "~3.0||~4.0||~5.0||~6.0||~7.0", "league/oauth2-client": "~2.0", "php": "^7.1|^8.0" }, @@ -5355,22 +5476,22 @@ ], "support": { "issues": "https://github.com/TheNetworg/oauth2-azure/issues", - "source": "https://github.com/TheNetworg/oauth2-azure/tree/v2.2.2" + "source": "https://github.com/TheNetworg/oauth2-azure/tree/v2.2.5" }, - "time": "2023-12-19T12:10:48+00:00" + "time": "2026-02-26T08:05:57+00:00" }, { "name": "twig/twig", - "version": "v3.21.1", + "version": "v3.23.0", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "285123877d4dd97dd7c11842ac5fb7e86e60d81d" + "reference": "a64dc5d2cc7d6cafb9347f6cd802d0d06d0351c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/285123877d4dd97dd7c11842ac5fb7e86e60d81d", - "reference": "285123877d4dd97dd7c11842ac5fb7e86e60d81d", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/a64dc5d2cc7d6cafb9347f6cd802d0d06d0351c9", + "reference": "a64dc5d2cc7d6cafb9347f6cd802d0d06d0351c9", "shasum": "" }, "require": { @@ -5424,7 +5545,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.21.1" + "source": "https://github.com/twigphp/Twig/tree/v3.23.0" }, "funding": [ { @@ -5436,7 +5557,7 @@ "type": "tidelift" } ], - "time": "2025-05-03T07:21:55+00:00" + "time": "2026-01-23T21:00:41+00:00" } ], "packages-dev": [ @@ -5508,16 +5629,16 @@ }, { "name": "symfony/web-profiler-bundle", - "version": "v6.4.25", + "version": "v6.4.34", "source": { "type": "git", "url": "https://github.com/symfony/web-profiler-bundle.git", - "reference": "4c1754d6b3ffe52e9eaed0d9a392eb43a60fc910" + "reference": "848bc5d5745500f855bb201d57ae066fd7e67448" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/4c1754d6b3ffe52e9eaed0d9a392eb43a60fc910", - "reference": "4c1754d6b3ffe52e9eaed0d9a392eb43a60fc910", + "url": "https://api.github.com/repos/symfony/web-profiler-bundle/zipball/848bc5d5745500f855bb201d57ae066fd7e67448", + "reference": "848bc5d5745500f855bb201d57ae066fd7e67448", "shasum": "" }, "require": { @@ -5570,7 +5691,7 @@ "dev" ], "support": { - "source": "https://github.com/symfony/web-profiler-bundle/tree/v6.4.25" + "source": "https://github.com/symfony/web-profiler-bundle/tree/v6.4.34" }, "funding": [ { @@ -5590,18 +5711,19 @@ "type": "tidelift" } ], - "time": "2025-08-07T12:02:05+00:00" + "time": "2026-02-05T15:19:06+00:00" } ], "aliases": [], "minimum-stability": "stable", "stability-flags": { + "apereo/phpcas": 20, "nikic/php-parser": 20 }, "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=8.1.0 <8.4.0", + "php": ">=8.1.0 <8.5.0", "ext-ctype": "*", "ext-dom": "*", "ext-gd": "*", @@ -5614,5 +5736,5 @@ "platform-overrides": { "php": "8.1.0" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.9.0" } diff --git a/core/bulkchange.class.inc.php b/core/bulkchange.class.inc.php index 8dd01b6ec..a9de370ce 100644 --- a/core/bulkchange.class.inc.php +++ b/core/bulkchange.class.inc.php @@ -199,7 +199,7 @@ class CellStatus_SearchIssue extends CellStatus_Issue * @param null $sAllowedValues : used for additional message that provides allowed values $sAllowedValues for current class * @param string|null $sAllowedValuesSearch : used to search all allowed values */ - public function __construct($sSerializedSearch, $sReason, $sClass = null, $sAllowedValues = null, string $sAllowedValuesSearch = null) + public function __construct($sSerializedSearch, $sReason, $sClass = null, $sAllowedValues = null, ?string $sAllowedValuesSearch = null) { parent::__construct(null, null, $sReason); $this->sSerializedSearch = $sSerializedSearch; @@ -876,7 +876,7 @@ class BulkChange return $aResults; } - protected function CreateObject(&$aResult, $iRow, $aRowData, CMDBChange $oChange = null) + protected function CreateObject(&$aResult, $iRow, $aRowData, ?CMDBChange $oChange = null) { $oTargetObj = MetaModel::NewObject($this->m_sClass); @@ -965,7 +965,7 @@ class BulkChange * @throws \MySQLException * @throws \MySQLHasGoneAwayException */ - protected function UpdateObject(&$aResult, $iRow, $oTargetObj, $aRowData, CMDBChange $oChange = null) + protected function UpdateObject(&$aResult, $iRow, $oTargetObj, $aRowData, ?CMDBChange $oChange = null) { $aResult[$iRow] = $this->PrepareObject($oTargetObj, $aRowData, $aErrors); @@ -1008,7 +1008,7 @@ class BulkChange * * @throws \BulkChangeException */ - protected function UpdateMissingObject(&$aResult, $iRow, $oTargetObj, CMDBChange $oChange = null) + protected function UpdateMissingObject(&$aResult, $iRow, $oTargetObj, ?CMDBChange $oChange = null) { $aResult[$iRow] = $this->PrepareMissingObject($oTargetObj, $aErrors); @@ -1043,7 +1043,7 @@ class BulkChange } } - public function Process(CMDBChange $oChange = null) + public function Process(?CMDBChange $oChange = null) { if ($oChange) { CMDBObject::SetCurrentChange($oChange); diff --git a/core/config.class.inc.php b/core/config.class.inc.php index 99d38a1ed..8dbc72ab4 100644 --- a/core/config.class.inc.php +++ b/core/config.class.inc.php @@ -928,7 +928,7 @@ class Config 'type' => 'string', 'description' => 'Actions that are available as direct buttons next to the "Actions" menu', // examples... not used - 'default' => 'UI:Menu:Modify,UI:Menu:New', + 'default' => 'UI:Menu:Modify,UI:Menu:New,UI:Menu:impacts_down,UI:Menu:impacts_up', 'value' => 'UI:Menu:Modify', 'source_of_value' => '', 'show_in_conf_sample' => true, @@ -1748,6 +1748,14 @@ class Config 'source_of_value' => '', 'show_in_conf_sample' => false, ], + 'security.force_login_when_no_delegated_authentication_endpoints_list' => [ + 'type' => 'bool', + 'description' => 'If true, when no execution policy is defined, the user will be forced to log in (instead of being automatically logged in with the default profile)', + 'default' => false, + 'value' => false, + 'source_of_value' => '', + 'show_in_conf_sample' => false, + ], 'behind_reverse_proxy' => [ 'type' => 'bool', 'description' => 'If true, then proxies custom header (X-Forwarded-*) are taken into account. Use only if the webserver is not publicly accessible (reachable only by the reverse proxy)', @@ -1954,11 +1962,6 @@ class Config */ protected $m_sDefaultLanguage; - /** - * @var string Type of login process allowed: form|basic|url|external - */ - protected $m_sAllowedLoginTypes; - /** * @var string Name of the PHP variable in which external authentication information is passed by the web server */ @@ -2032,7 +2035,6 @@ class Config $this->m_iFastReloadInterval = DEFAULT_FAST_RELOAD_INTERVAL; $this->m_bSecureConnectionRequired = DEFAULT_SECURE_CONNECTION_REQUIRED; $this->m_sDefaultLanguage = 'EN US'; - $this->m_sAllowedLoginTypes = DEFAULT_ALLOWED_LOGIN_TYPES; $this->m_sExtAuthVariable = DEFAULT_EXT_AUTH_VARIABLE; $this->m_aCharsets = []; $this->m_bQueryCacheEnabled = DEFAULT_QUERY_CACHE_ENABLED; @@ -2179,7 +2181,6 @@ class Config $this->m_aModuleSettings = isset($MyModuleSettings) ? $MyModuleSettings : []; $this->m_sDefaultLanguage = isset($MySettings['default_language']) ? trim($MySettings['default_language']) : 'EN US'; - $this->m_sAllowedLoginTypes = isset($MySettings['allowed_login_types']) ? trim($MySettings['allowed_login_types']) : DEFAULT_ALLOWED_LOGIN_TYPES; $this->m_sExtAuthVariable = isset($MySettings['ext_auth_variable']) ? trim($MySettings['ext_auth_variable']) : DEFAULT_EXT_AUTH_VARIABLE; $this->m_sEncryptionKey = isset($MySettings['encryption_key']) ? trim($MySettings['encryption_key']) : $this->m_sEncryptionKey; $this->m_sEncryptionLibrary = isset($MySettings['encryption_library']) ? trim($MySettings['encryption_library']) : $this->m_sEncryptionLibrary; @@ -2339,7 +2340,7 @@ class Config public function GetAllowedLoginTypes() { - return explode('|', $this->m_sAllowedLoginTypes); + return explode('|', $this->m_aSettings['allowed_login_types']['value']); } public function GetExternalAuthenticationVariable() @@ -2417,7 +2418,7 @@ class Config public function SetAllowedLoginTypes($aAllowedLoginTypes) { - $this->m_sAllowedLoginTypes = implode('|', $aAllowedLoginTypes); + $this->Set('allowed_login_types', implode('|', $aAllowedLoginTypes)); } /** @@ -2494,7 +2495,6 @@ class Config $aSettings['fast_reload_interval'] = $this->m_iFastReloadInterval; $aSettings['secure_connection_required'] = $this->m_bSecureConnectionRequired; $aSettings['default_language'] = $this->m_sDefaultLanguage; - $aSettings['allowed_login_types'] = $this->m_sAllowedLoginTypes; $aSettings['ext_auth_variable'] = $this->m_sExtAuthVariable; $aSettings['encryption_key'] = $this->m_sEncryptionKey; $aSettings['encryption_library'] = $this->m_sEncryptionLibrary; @@ -2598,7 +2598,6 @@ class Config // Old fashioned remaining values $aOtherValues = [ 'default_language' => $this->m_sDefaultLanguage, - 'allowed_login_types' => $this->m_sAllowedLoginTypes, 'ext_auth_variable' => $this->m_sExtAuthVariable, 'encryption_key' => $this->m_sEncryptionKey, 'encryption_library' => $this->m_sEncryptionLibrary, diff --git a/core/csvbulkexport.class.inc.php b/core/csvbulkexport.class.inc.php index bc0d957ac..0e4ded346 100644 --- a/core/csvbulkexport.class.inc.php +++ b/core/csvbulkexport.class.inc.php @@ -5,6 +5,7 @@ * @license http://opensource.org/licenses/AGPL-3.0 */ +use Combodo\iTop\Application\Helper\ExportHelper; use Combodo\iTop\Application\UI\Base\Component\FieldSet\FieldSetUIBlockFactory; use Combodo\iTop\Application\UI\Base\Component\Html\Html; use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory; @@ -13,7 +14,6 @@ use Combodo\iTop\Application\UI\Base\Component\Input\Select\SelectUIBlockFactory use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory; use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\Column\ColumnUIBlockFactory; use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\MultiColumnUIBlockFactory; -use Combodo\iTop\Application\Helper\ExportHelper; use Combodo\iTop\Application\WebPage\Page; use Combodo\iTop\Application\WebPage\WebPage; @@ -55,6 +55,8 @@ class CSVBulkExport extends TabularBulkExport $this->aStatusInfo['charset'] = strtoupper(utils::ReadParam('charset', 'UTF-8', true, 'raw_data')); $this->aStatusInfo['formatted_text'] = (bool)utils::ReadParam('formatted_text', 0, true); + $this->aStatusInfo['ignore_excel_sanitization'] = (bool)utils::ReadParam('ignore_excel_sanitization', 0, true, utils::ENUM_SANITIZATION_FILTER_INTEGER); + $sDateFormatRadio = utils::ReadParam('csv_date_format_radio', ''); switch ($sDateFormatRadio) { case 'default': @@ -223,6 +225,10 @@ class CSVBulkExport extends TabularBulkExport $oRadioCustom->GetInput()->AddCSSClass('ibo-input-checkbox'); $oFieldSetDate->AddSubBlock($oRadioCustom); + $oFieldSetSecurity = FieldSetUIBlockFactory::MakeStandard(Dict::S('Core:BulkExport:Security')); + $oMulticolumn->AddColumn(ColumnUIBlockFactory::MakeForBlock($oFieldSetSecurity)); + $oFieldSetSecurity->AddSubBlock(ExportHelper::GetInputForSanitizeExcelExport()); + $oP->add_ready_script( <<GetAsCSV($sAttCode), '"'); } + + // If the option to ignore Excel sanitization is not set or explicitly set to false, apply sanitization + if (!(array_key_exists('ignore_excel_sanitization', $this->aStatusInfo)) || $this->aStatusInfo['ignore_excel_sanitization'] === false) { + return ExportHelper::SanitizeField($sRet, $this->aStatusInfo['text_qualifier'] ?? ''); + } + + // The option to ignore Excel sanitization is explicitly set to true: return the raw value without sanitization return $sRet; } @@ -337,6 +350,12 @@ EOF $sField = $oObj->GetAsCSV($sAttCode, $this->aStatusInfo['separator'], $this->aStatusInfo['text_qualifier'], $this->bLocalizeOutput, !$this->aStatusInfo['formatted_text']); } } + + // If the option to ignore Excel sanitization is not set or absent, sanitize the field + if (!(array_key_exists('ignore_excel_sanitization', $this->aStatusInfo)) || $this->aStatusInfo['ignore_excel_sanitization'] === false) { + $sField = ExportHelper::SanitizeField($sField, $this->aStatusInfo['text_qualifier']); + } + if ($this->aStatusInfo['charset'] != 'UTF-8') { // Note: due to bugs in the glibc library it's safer to call iconv on the smallest possible string // and thus to convert field by field and not the whole row or file at once (see ticket N°991) diff --git a/core/dbobject.class.php b/core/dbobject.class.php index 5367f10ff..9c82be25a 100644 --- a/core/dbobject.class.php +++ b/core/dbobject.class.php @@ -2567,7 +2567,7 @@ abstract class DBObject implements iDisplay * * @see \RestUtils::FindObjectFromKey for the same check in the REST endpoint */ - final public function CheckChangedExtKeysValues(callable $oIsObjectLoadableCallback = null) + final public function CheckChangedExtKeysValues(?callable $oIsObjectLoadableCallback = null) { if (is_null($oIsObjectLoadableCallback)) { $oIsObjectLoadableCallback = function ($sClass, $sId) { @@ -3727,7 +3727,7 @@ abstract class DBObject implements iDisplay * @throws \MySQLException * @throws \OQLException */ - private function ActivateOnObjectUpdateTriggers(?DBObject $oObject, array $aAttributes = null): void + private function ActivateOnObjectUpdateTriggers(?DBObject $oObject, ?array $aAttributes = null): void { if (is_null($oObject)) { return; diff --git a/core/dbsearch.class.php b/core/dbsearch.class.php index be26a5628..bcaf58236 100644 --- a/core/dbsearch.class.php +++ b/core/dbsearch.class.php @@ -650,7 +650,7 @@ abstract class DBSearch * * @throws OQLException */ - public static function FromOQL($sQuery, $aParams = null, ModelReflection $oMetaModel = null) + public static function FromOQL($sQuery, $aParams = null, ?ModelReflection $oMetaModel = null) { if (empty($sQuery)) { return null; diff --git a/core/dbunionsearch.class.php b/core/dbunionsearch.class.php index 9d3836f0e..0d300674b 100644 --- a/core/dbunionsearch.class.php +++ b/core/dbunionsearch.class.php @@ -59,7 +59,7 @@ class DBUnionSearch extends DBSearch public function AllowAllData($bAllowAllData = true) { foreach ($this->aSearches as $oSearch) { - $oSearch->AllowAllData(); + $oSearch->AllowAllData($bAllowAllData); } } diff --git a/core/designdocument.class.inc.php b/core/designdocument.class.inc.php index 2e324f38b..65cd295b2 100644 --- a/core/designdocument.class.inc.php +++ b/core/designdocument.class.inc.php @@ -41,7 +41,7 @@ use utils; /** * Class \Combodo\iTop\DesignDocument * - * A design document is the DOM tree that modelize behaviors. One of its + * A design document is the DOM tree that models behaviors. One of its * characteristics is that it can be altered by the mean of the same kind of document. * */ @@ -453,7 +453,7 @@ class DesignElement extends \DOMElement * @throws Exception * @since 3.1.2 3.2.0 N°6974 */ - public static function _FindNode(DOMNode $oParent, DesignElement $oRefNode, string $sSearchId = null): ?DesignElement + public static function _FindNode(DOMNode $oParent, DesignElement $oRefNode, ?string $sSearchId = null): ?DesignElement { $oNodes = self::_FindNodes($oParent, $oRefNode, $sSearchId); if ($oNodes instanceof DOMNodeList) { @@ -477,7 +477,7 @@ class DesignElement extends \DOMElement * @return \DOMNodeList|false|mixed * @since 3.1.2 3.2.0 N°6974 */ - public static function _FindNodes(DOMNode $oParent, DesignElement $oRefNode, string $sSearchId = null) + public static function _FindNodes(DOMNode $oParent, DesignElement $oRefNode, ?string $sSearchId = null) { if ($oParent instanceof DOMDocument) { $oDoc = $oParent->firstChild->ownerDocument; diff --git a/core/displayablegraph.class.inc.php b/core/displayablegraph.class.inc.php index f1e378cdf..180bff730 100644 --- a/core/displayablegraph.class.inc.php +++ b/core/displayablegraph.class.inc.php @@ -632,7 +632,7 @@ class DisplayableGroupNode extends DisplayableNode $this->aObjects = []; } - public function AddObject(DBObject $oObj = null) + public function AddObject(?DBObject $oObj = null) { if (is_object($oObj)) { $sPrevClass = $this->GetObjectClass(); diff --git a/core/excelbulkexport.class.inc.php b/core/excelbulkexport.class.inc.php index 6f4632962..8cf9be44e 100644 --- a/core/excelbulkexport.class.inc.php +++ b/core/excelbulkexport.class.inc.php @@ -5,13 +5,13 @@ * @license http://opensource.org/licenses/AGPL-3.0 */ +use Combodo\iTop\Application\Helper\ExportHelper; use Combodo\iTop\Application\UI\Base\Component\FieldSet\FieldSetUIBlockFactory; 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\Panel\PanelUIBlockFactory; use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\Column\ColumnUIBlockFactory; use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\MultiColumnUIBlockFactory; -use Combodo\iTop\Application\Helper\ExportHelper; use Combodo\iTop\Application\WebPage\Page; use Combodo\iTop\Application\WebPage\WebPage; @@ -63,6 +63,8 @@ class ExcelBulkExport extends TabularBulkExport // Export from the command line (or scripted) => default format is SQL, as in previous versions of iTop, unless specified otherwise $this->aStatusInfo['date_format'] = utils::ReadParam('date_format', (string)AttributeDateTime::GetSQLFormat(), true, 'raw_data'); } + + $this->aStatusInfo['ignore_excel_sanitization'] = (bool)utils::ReadParam('ignore_excel_sanitization', 0, true, utils::ENUM_SANITIZATION_FILTER_INTEGER); } public function EnumFormParts() @@ -121,6 +123,10 @@ class ExcelBulkExport extends TabularBulkExport $oRadioCustom->GetInput()->AddCSSClass('ibo-input-checkbox'); $oFieldSetDate->AddSubBlock($oRadioCustom); + $oFieldSetSecurity = FieldSetUIBlockFactory::MakeStandard(Dict::S('Core:BulkExport:Security')); + $oMulticolumn->AddColumn(ColumnUIBlockFactory::MakeForBlock($oFieldSetSecurity)); + $oFieldSetSecurity->AddSubBlock(ExportHelper::GetInputForSanitizeExcelExport()); + $oP->add_ready_script( <<aStatusInfo)) || $this->aStatusInfo['ignore_excel_sanitization'] === false) { + return ExportHelper::SanitizeField($sRet, ''); + } + return $sRet; } diff --git a/core/inlineimage.class.inc.php b/core/inlineimage.class.inc.php index b0cb500a8..252b425fa 100644 --- a/core/inlineimage.class.inc.php +++ b/core/inlineimage.class.inc.php @@ -259,13 +259,18 @@ class InlineImage extends DBObject * that refer to an InlineImage (detected via the attribute data-img-id="") so that * the URL is consistent with the current URL of the application. * - * @param string $sHtml The HTML fragment to process +N°8681 * @param string|null $sHtml The HTML fragment to process * * @return string The modified HTML * @throws \Exception + * + * @since 3.3.0 N°8681 Add type hint for parameters and return value */ - public static function FixUrls($sHtml) + public static function FixUrls(string|null $sHtml): string { + // N°8681 - Ensure to have a string value + $sHtml = $sHtml ?? ''; + $aNeedles = []; $aReplacements = []; // Find img tags with an attribute data-img-id @@ -293,6 +298,46 @@ class InlineImage extends DBObject return $sHtml; } + /** + * Replace tags with a data-img-id attribute by the actual image in base64 representation + * so that the image can be displayed even if the download URL is not accessible (e.g. in unauthenticated approval templates) + * + * @param string $sHtml The HTML fragment to process + * + * @return String The modified HTML + * @since 3.2.3 + */ + public static function ReplaceInlineImagesWithBase64Representation(string $sHtml): String + { + return preg_replace_callback( + '/]*'.static::DOM_ATTR_ID.'="(\d+)"[^>]*>/i', + function ($matches) { + + // Extract inline image ID from the tag + $id = $matches[1]; + + try { + // Retrieve inline image + $oInline = MetaModel::GetObject(InlineImage::class, $id, true, true); + $oOrmDocument = $oInline->Get('contents'); + + // Replace src image by the base64 representation + $sInlineImageAsBase64 = base64_encode($oOrmDocument->GetData()); + $sDataUri = 'data:'.$oOrmDocument->GetMimeType().';base64,'.$sInlineImageAsBase64; + $sImage = preg_replace('/src=["\'][^"\']+["\']/', 'src="'.$sDataUri.'"', $matches[0]); + + // Remove sensitive information (the image ID and secret) from the tag + $sImage = preg_replace('/'.static::DOM_ATTR_ID.'="\d+"\s+'.static::DOM_ATTR_SECRET.'="\w+"/', '', $sImage); + } catch (Exception $e) { + $sImage = ''.Dict::S('UI:MissingInlineImage').''; + } + + return $sImage; + }, + $sHtml + ); + } + /** * Add an extra attribute data-img-id for images which are based on an actual InlineImage * so that we can later reconstruct the full "src" URL when needed @@ -389,7 +434,7 @@ JS * Resize an image so that it fits the maximum width/height defined in the config file * @param ormDocument $oImage The original image stored as an array (content / mimetype / filename) * @return ormDocument The resampled image (or the original one if it already fit) - * @deprecated Replaced by ormDocument::ResizeImageToFit + * @deprecated since 3.3.0 Replaced by ormDocument::ResizeImageToFit */ public static function ResizeImageToFit(ormDocument $oImage, &$aDimensions = null) { diff --git a/core/kpi.class.inc.php b/core/kpi.class.inc.php index fd6f83feb..977b3da44 100644 --- a/core/kpi.class.inc.php +++ b/core/kpi.class.inc.php @@ -1,18 +1,20 @@ 0) { @@ -71,6 +76,7 @@ class ExecutionKPI return true; } } + return false; } @@ -97,7 +103,7 @@ class ExecutionKPI $sFor = self::$m_sAllowedUser == '*' ? 'EVERYBODY' : "'".trim(self::$m_sAllowedUser)."'"; $sSlowQueries = ''; if (self::$m_fSlowQueries > 0) { - $sSlowQueries = ". Slow Queries: ".self::$m_fSlowQueries."s"; + $sSlowQueries = '. Slow Queries: '.self::$m_fSlowQueries.'s'; } $aExtensions = []; @@ -127,7 +133,7 @@ class ExecutionKPI $sRequest .= ' operation: '.$_POST['operation']; } - $fStop = MyHelpers::getmicrotime(); + $fStop = microtime(true); if (($fStop - $fItopStarted) > self::$m_fSlowQueries) { // Invoke extensions to log the KPI operation /** @var \iKPILoggerExtension $oExtensionInstance */ @@ -151,17 +157,17 @@ class ExecutionKPI $sTableStyle = 'background-color: #ccc; margin: 10px;'; - $sHtml = "
"; + $sHtml = '
'; $sHtml .= "
"; $sHtml .= "

KPIs - $sRequest

"; $oStarted = DateTime::createFromFormat('U.u', $fItopStarted); $sHtml .= '

'.$oStarted->format('Y-m-d H:i:s.u').'

'; - $sHtml .= "

log_kpi_user_id: ".UserRights::GetUserId()."

"; - $sHtml .= "
"; + $sHtml .= '

log_kpi_user_id: '.UserRights::GetUserId().'

'; + $sHtml .= '
'; $sHtml .= ""; - $sHtml .= ""; - $sHtml .= " "; - $sHtml .= ""; + $sHtml .= ''; + $sHtml .= ' '; + $sHtml .= ''; foreach (self::$m_aExecData as $aOpStats) { $sOperation = $aOpStats['op']; $sBegin = round($aOpStats['time_begin'], 3); @@ -180,12 +186,12 @@ class ExecutionKPI } } - $sHtml .= ""; + $sHtml .= ''; $sHtml .= " "; - $sHtml .= ""; + $sHtml .= ''; } - $sHtml .= "
OperationBeginEndDurationMemory startMemory endMemory peak
OperationBeginEndDurationMemory startMemory endMemory peak
$sOperation$sBegin$sEnd$sDuration$sMemBegin$sMemEnd$sMemPeak
"; - $sHtml .= "
"; + $sHtml .= ''; + $sHtml .= '
'; $aConsolidatedStats = []; foreach (self::$m_aStats as $sOperation => $aOpStats) { @@ -208,20 +214,20 @@ class ExecutionKPI } } $aConsolidatedStats[$sOperation] = [ - 'count' => $iTotalOp, + 'count' => $iTotalOp, 'duration' => $fTotalOp, - 'min' => $fMinOp, - 'max' => $fMaxOp, - 'avg' => $fTotalOp / $iTotalOp, + 'min' => $fMinOp, + 'max' => $fMaxOp, + 'avg' => $fTotalOp / $iTotalOp, 'max_args' => $sMaxOpArguments, ]; } - $sHtml .= "
"; + $sHtml .= '
'; $sHtml .= ""; - $sHtml .= ""; - $sHtml .= " "; - $sHtml .= ""; + $sHtml .= ''; + $sHtml .= ' '; + $sHtml .= ''; foreach ($aConsolidatedStats as $sOperation => $aOpStats) { $sOperation = ''.$sOperation.''; $sCount = $aOpStats['count']; @@ -230,14 +236,14 @@ class ExecutionKPI $sMax = ''.round($aOpStats['max'], 3).''; $sAvg = round($aOpStats['avg'], 3); - $sHtml .= ""; + $sHtml .= ''; $sHtml .= " "; - $sHtml .= ""; + $sHtml .= ''; } - $sHtml .= "
OperationCountDurationMinMaxAvg
OperationCountDurationMinMaxAvg
$sOperation$sCount$sDuration$sMin$sMax$sAvg
"; - $sHtml .= "
"; + $sHtml .= ''; + $sHtml .= '
'; - $sHtml .= "
"; + $sHtml .= ''; $sHtml .= "

Next page stats

"; @@ -287,18 +293,18 @@ class ExecutionKPI $sOperationHtml = ''.$sOperation.''; $sHtml .= "

$sOperationHtml

"; $sHtml .= ""; - $sHtml .= ""; - $sHtml .= " "; - $sHtml .= ""; + $sHtml .= ''; + $sHtml .= ' '; + $sHtml .= ''; $bDisplayHeader = false; } - $sHtml .= ""; + $sHtml .= ''; $sHtml .= " "; - $sHtml .= ""; + $sHtml .= ''; } } if (!$bDisplayHeader) { - $sHtml .= "
Operation details (+ blame caller if log_kpi_duration = 2)CountDurationMinMax
Operation details (+ blame caller if log_kpi_duration = 2)CountDurationMinMax
$sHtmlArguments$iCountInter$sTotalInter$sMinInter$sMaxInter
"; + $sHtml .= ''; $sHtml .= "

Back to page stats

"; } self::Report($sHtml); @@ -333,39 +339,50 @@ class ExecutionKPI $aNewEntry = null; - $fStarted = $this->m_fStarted; - $fStopped = $this->m_fStarted; - if (self::$m_bEnabled_Duration) { - $fStopped = MyHelpers::getmicrotime(); - $aNewEntry = [ - 'op' => $sOperationDesc, - 'time_begin' => $this->m_fStarted - $fItopStarted, - 'time_end' => $fStopped - $fItopStarted, - ]; - // Reset for the next operation (if the object is recycled) - $this->m_fStarted = $fStopped; + if (is_null(static::$fLastReportTime)) { + static::$fLastReportTime = $fItopStarted; } - $iInitialMemory = is_null($this->m_iInitialMemory) ? 0 : $this->m_iInitialMemory; - $iCurrentMemory = 0; - $iPeakMemory = 0; + if (is_null(static::$iLastReportMemory)) { + global $iItopInitialMemory; + static::$iLastReportMemory = $iItopInitialMemory; + } + + $fStarted = static::$fLastReportTime; + $fStopped = microtime(true); + if (self::$m_bEnabled_Duration) { + $aNewEntry = [ + 'op' => $sOperationDesc, + 'time_begin' => $fStarted - $fItopStarted, + 'time_end' => $fStopped - $fItopStarted, + ]; + } + static::$fLastReportTime = $fStopped; + + $iInitialMemory = static::$iLastReportMemory; + $iCurrentMemory = $iInitialMemory; + $iPeakMemory = $iInitialMemory; if (self::$m_bEnabled_Memory) { $iCurrentMemory = self::memory_get_usage(); if (is_null($aNewEntry)) { $aNewEntry = ['op' => $sOperationDesc]; } - $aNewEntry['mem_begin'] = $this->m_iInitialMemory; + $aNewEntry['mem_begin'] = $iInitialMemory; $aNewEntry['mem_end'] = $iCurrentMemory; $iPeakMemory = self::memory_get_peak_usage(); $aNewEntry['mem_peak'] = $iPeakMemory; // Reset for the next operation (if the object is recycled) - $this->m_iInitialMemory = $iCurrentMemory; + static::$iLastReportMemory = $iCurrentMemory; } if (self::$m_bEnabled_Duration || self::$m_bEnabled_Memory) { - // Invoke extensions to log the KPI operation - /** @var \iKPILoggerExtension $oExtensionInstance */ - foreach (MetaModel::EnumPlugins('iKPILoggerExtension') as $oExtensionInstance) { + $aCallstack = ['callstack' => $this->GetCallStack()]; + if (static::$bMetamodelStarted) { + foreach (static::$aBootstrapOperations as $oLog) { + $this->LogOperation($oLog); + } + static::$aBootstrapOperations = []; + // Invoke extensions to log the KPI operation $sExtension = ModuleService::GetInstance()->GetModuleNameFromCallStack(1); $oKPILogData = new KpiLogData( KpiLogData::TYPE_REPORT, @@ -376,9 +393,24 @@ class ExecutionKPI $sExtension, $iInitialMemory, $iCurrentMemory, - $iPeakMemory + $iPeakMemory, + $aCallstack ); - $oExtensionInstance->LogOperation($oKPILogData); + $this->LogOperation($oKPILogData); + } else { + $oKPILogData = new KpiLogData( + KpiLogData::TYPE_REPORT, + 'Step', + $sOperationDesc, + $fStarted, + $fStopped, + '', + $iInitialMemory, + $iCurrentMemory, + $iPeakMemory, + $aCallstack + ); + static::$aBootstrapOperations[] = $oKPILogData; } } @@ -388,13 +420,21 @@ class ExecutionKPI $this->ResetCounters(); } + private function LogOperation(KpiLogData $oKPILogData): void + { + /** @var \iKPILoggerExtension $oExtensionInstance */ + foreach (MetaModel::EnumPlugins('iKPILoggerExtension') as $oExtensionInstance) { + $oExtensionInstance->LogOperation($oKPILogData); + } + } + /** * Compute statistics for a call to an extension * Note: not working in dev mode (with links to env-production) * * @param object|string $object object called - * @param string $sMethod method called on the object - * @param string $sMessage additional message + * @param string $sMethod method called on the object + * @param string $sMessage additional message * * @return bool true if an extension was found for this object::method * @throws \ReflectionException @@ -423,21 +463,23 @@ class ExecutionKPI $fDuration = 0; if (self::$m_bEnabled_Duration) { - $fStopped = MyHelpers::getmicrotime(); + $fStopped = microtime(true); $fDuration = $fStopped - $this->m_fStarted; $aCallstack = []; if (self::$m_bGenerateLegacyReport) { if (self::$m_bBlameCaller) { $aCallstack = MyHelpers::get_callstack(1); self::$m_aStats[$sOperation][$sArguments][] = [ - 'time' => $fDuration, - 'callers' => $aCallstack, + 'time' => $fDuration, + 'callers' => $aCallstack, ]; } else { self::$m_aStats[$sOperation][$sArguments][] = [ - 'time' => $fDuration, + 'time' => $fDuration, ]; } + } else { + $aCallstack = ['callstack' => $this->GetCallStack()]; } $iInitialMemory = is_null($this->m_iInitialMemory) ? 0 : $this->m_iInitialMemory; @@ -448,33 +490,45 @@ class ExecutionKPI $iPeakMemory = self::memory_get_peak_usage(); } - // Invoke extensions to log the KPI operation - /** @var \iKPILoggerExtension $oExtensionInstance */ - foreach (MetaModel::EnumPlugins('iKPILoggerExtension') as $oExtensionInstance) { - //$sExtension = ModuleService::GetInstance()->GetModuleNameFromCallStack(1); - $sExtension = ''; + if (static::$bMetamodelStarted) { + foreach (static::$aBootstrapOperations as $oLog) { + $this->LogOperation($oLog); + } + static::$aBootstrapOperations = []; $oKPILogData = new KpiLogData( KpiLogData::TYPE_STATS, $sOperation, $sArguments, $this->m_fStarted, $fStopped, - $sExtension, + '', $iInitialMemory, $iCurrentMemory, $iPeakMemory, $aCallstack ); - $oExtensionInstance->LogOperation($oKPILogData); + $this->LogOperation($oKPILogData); + } else { + $oKPILogData = new KpiLogData( + KpiLogData::TYPE_STATS, + $sOperation, + $sArguments, + $this->m_fStarted, + $fStopped, + '', + $iInitialMemory, + $iCurrentMemory, + $iPeakMemory, + $aCallstack + ); + static::$aBootstrapOperations[] = $oKPILogData; } } } protected function ResetCounters() { - if (self::$m_bEnabled_Duration) { - $this->m_fStarted = microtime(true); - } + $this->m_fStarted = microtime(true); if (self::$m_bEnabled_Memory) { $this->m_iInitialMemory = self::memory_get_usage(); @@ -503,7 +557,33 @@ class ExecutionKPI if (function_exists('memory_get_peak_usage')) { return memory_get_peak_usage($bRealUsage); } + // PHP > 5.2.1 - this verb depends on a compilation option return 0; } + + /* + * ModuleHandlerApiInterface methods + */ + + public static function OnMetaModelStarted() + { + static::$bMetamodelStarted = true; + } + + public function RegisterEventsAndListeners() + { + EventService::RegisterListener(ApplicationEvents::APPLICATION_EVENT_METAMODEL_STARTED, [$this, 'OnMetaModelStarted']); + } + + private function GetCallStack(): string + { + $aCallStack = MyHelpers::get_callstack(2); + $sCallStack = "Call stack:\n"; + foreach ($aCallStack as $index => $aLine) { + $sCallStack .= "#$index ".$aLine['File'].'('.$aLine['Line'].'): '.$aLine['Function']."\n"; + } + + return $sCallStack; + } } diff --git a/core/log.class.inc.php b/core/log.class.inc.php index b79703ebf..0e4962c43 100644 --- a/core/log.class.inc.php +++ b/core/log.class.inc.php @@ -691,6 +691,28 @@ abstract class LogAPI static::$m_oMockMetaModelConfig = $oMetaModelConfig; } + public static function Exception(string $sMessage, throwable $oException, string $sChannel = null, array $aContext = []): void + { + $aErrorLogs = []; + $aErrorLogs[] = static::PrepareErrorLog($sMessage, $oException, $aContext); + $oException = $oException->getPrevious(); + while ($oException !== null) { + $aErrorLogs[] = static::PrepareErrorLog($oException->getMessage(), $oException, $aContext, true); + $oException = $oException->getPrevious(); + } + $aErrorLogs = array_reverse($aErrorLogs); + foreach ($aErrorLogs as $aErrorLog) { + static::Error($aErrorLog['message'], $sChannel, $aErrorLog['context']); + } + } + + private static function PrepareErrorLog(string $sMessage, throwable $oException, array $aContext, bool $isPrevious = false): array + { + $aContext['Error Message'] = $oException->getMessage(); + $aContext['Stack Trace'] = $oException->getTraceAsString(); + return ['message' => ($isPrevious ? "Previous " : '')."Exception: $sMessage", 'context' => $aContext]; + } + public static function Error($sMessage, $sChannel = null, $aContext = []) { static::Log(self::LEVEL_ERROR, $sMessage, $sChannel, $aContext); diff --git a/core/modelreflection.class.inc.php b/core/modelreflection.class.inc.php index 3e10c0bdd..2103e0081 100644 --- a/core/modelreflection.class.inc.php +++ b/core/modelreflection.class.inc.php @@ -55,6 +55,11 @@ abstract class ModelReflection abstract public function GetFiltersList($sClass); abstract public function IsValidFilterCode($sClass, $sFilterCode); + /** + * @since 3.3.0 + */ + abstract public function IsAbstract($sClass): bool; + /** * @param string $sOQL * @@ -148,7 +153,7 @@ class ModelReflectionRuntime extends ModelReflection $sAttributeClass = get_class($oAttDef); if ($aScope != null) { foreach ($aScope as $sScopeClass) { - if (($sAttributeClass == $sScopeClass) || is_subclass_of($sAttributeClass, $sScopeClass)) { + if (is_a($sAttributeClass, $sScopeClass, true)) { $aAttributes[$sAttCode] = $sAttributeClass; break; } @@ -230,6 +235,11 @@ class ModelReflectionRuntime extends ModelReflection return MetaModel::IsValidFilterCode($sClass, $sFilterCode); } + public function IsAbstract($sClass): bool + { + return MetaModel::IsAbstract($sClass); + } + public function GetQuery($sOQL) { return new QueryReflectionRuntime($sOQL, $this); diff --git a/core/oql/build/PHP/ParserGenerator/Data.php b/core/oql/build/PHP/ParserGenerator/Data.php index 39e62597c..c406c7cf7 100644 --- a/core/oql/build/PHP/ParserGenerator/Data.php +++ b/core/oql/build/PHP/ParserGenerator/Data.php @@ -1656,7 +1656,7 @@ class PHP_ParserGenerator_Data function emit_code($out, PHP_ParserGenerator_Rule $rp, &$lineno) { $linecnt = 0; - + /* Generate code to do the reduce action */ if ($rp->code) { $this->tplt_linedir($out, $rp->line, $this->filename); diff --git a/core/oql/expression.class.inc.php b/core/oql/expression.class.inc.php index ef5f82946..0b017791a 100644 --- a/core/oql/expression.class.inc.php +++ b/core/oql/expression.class.inc.php @@ -2103,12 +2103,18 @@ class VariableExpression extends UnaryExpression /** * Evaluate the value of the expression + * * @param array $aArgs - * @throws \Exception if terms cannot be evaluated as scalars -*/ + * + * @return mixed + * @throws \MissingQueryArgument + */ public function Evaluate(array $aArgs) { - throw new Exception('not implemented yet'); + if (!isset($aArgs[$this->m_sName])) { + throw new MissingQueryArgument('Missing variable expression argument', array('expecting'=>$this->m_sName)); + } + return $aArgs[$this->m_sName]; } /** diff --git a/core/oql/oql-parser.php b/core/oql/oql-parser.php index 9168a3611..aff1e52bf 100644 --- a/core/oql/oql-parser.php +++ b/core/oql/oql-parser.php @@ -1084,7 +1084,7 @@ static public $yy_action = array( function yy_find_shift_action($iLookAhead) { $stateno = $this->yystack[$this->yyidx]->stateno; - + /* if ($this->yyidx < 0) return self::YY_NO_ACTION; */ if (!isset(self::$yy_shift_ofst[$stateno])) { // no shift actions @@ -1767,7 +1767,7 @@ throw new OQLParserParseFailureException($this->m_sSourceQuery, $this->m_iLine, function yy_syntax_error($yymajor, $TOKEN) { #line 25 "..\oql-parser.y" - + throw new OQLParserSyntaxErrorException($this->m_sSourceQuery, $this->m_iLine, $this->m_iCol, $this->tokenName($yymajor), $TOKEN); #line 1779 "..\oql-parser.php" } @@ -1806,7 +1806,7 @@ throw new OQLParserSyntaxErrorException($this->m_sSourceQuery, $this->m_iLine, $ // $yyact; /* The parser action. */ // $yyendofinput; /* True if we are at the end of input */ $yyerrorhit = 0; /* True if yymajor has invoked an error */ - + /* (re)initialize the parser, if necessary */ if ($this->yyidx === null || $this->yyidx < 0) { /* if ($yymajor == 0) return; // not sure why this was here... */ @@ -1819,7 +1819,7 @@ throw new OQLParserSyntaxErrorException($this->m_sSourceQuery, $this->m_iLine, $ array_push($this->yystack, $x); } $yyendofinput = ($yymajor==0); - + if (self::$yyTraceFILE) { fprintf( self::$yyTraceFILE, @@ -1828,7 +1828,7 @@ throw new OQLParserSyntaxErrorException($this->m_sSourceQuery, $this->m_iLine, $ self::$yyTokenName[$yymajor] ); } - + do { $yyact = $this->yy_find_shift_action($yymajor); if ($yymajor < self::YYERRORSYMBOL @@ -2002,7 +2002,7 @@ class OQLParser extends OQLParserRaw $this->m_sSourceQuery = $sQuery; // no constructor - parent::__construct(); } - + public function doParse($token, $value, $iCurrPosition = 0) { $this->m_iColPrev = $this->m_iCol; @@ -2016,7 +2016,7 @@ class OQLParser extends OQLParserRaw $this->doParse(0, 0); return $this->my_result; } - + public function __destruct() { // Bug in the original destructor, causing an infinite loop ! diff --git a/core/oql/oqlexception.class.inc.php b/core/oql/oqlexception.class.inc.php index 4df947e4b..e940d9dbe 100644 --- a/core/oql/oqlexception.class.inc.php +++ b/core/oql/oqlexception.class.inc.php @@ -72,9 +72,15 @@ class OQLException extends CoreException } else { - $sExpectations = '{'.implode(', ', $this->m_aExpecting).'}'; + $sMessage = "$sIssue - found '{$this->m_sUnexpected}' at $iCol in '$sInput'"; + if (count($this->m_aExpecting) < 30) { + $sExpectations = '{'.implode(', ', $this->m_aExpecting).'}'; + $sMessage .= ', expecting '.json_encode($sExpectations); + } $sSuggest = self::FindClosestString($this->m_sUnexpected, $this->m_aExpecting); - $sMessage = "$sIssue - found '{$this->m_sUnexpected}' at $iCol in '$sInput', expecting $sExpectations, I would suggest to use '$sSuggest'"; + if (strlen($sSuggest) > 0) { + $sMessage .= ", I would suggest to use ".json_encode($sSuggest); + } } // make sure everything is assigned properly @@ -155,5 +161,3 @@ class OQLException extends CoreException return $sRet; } } - -?> diff --git a/core/oql/oqlquery.class.inc.php b/core/oql/oqlquery.class.inc.php index 24889d356..f29899ff4 100644 --- a/core/oql/oqlquery.class.inc.php +++ b/core/oql/oqlquery.class.inc.php @@ -57,15 +57,15 @@ class OqlName { return $this->m_iPos; } - + public function __toString() { return $this->m_sValue; - } + } } /** - * + * * Store hexadecimal values as strings so that we can support 64-bit values * */ @@ -77,12 +77,12 @@ class OqlHexValue { $this->m_sValue = $sValue; } - + public function __toString() { return $this->m_sValue; } - + } class OqlJoinSpec @@ -109,6 +109,7 @@ class OqlJoinSpec { return $this->m_oClass->GetValue(); } + public function GetClassAlias() { return $this->m_oClassAlias->GetValue(); @@ -118,6 +119,7 @@ class OqlJoinSpec { return $this->m_oClass; } + public function GetClassAliasDetails() { return $this->m_oClassAlias; @@ -127,10 +129,12 @@ class OqlJoinSpec { return $this->m_oLeftField; } + public function GetRightField() { return $this->m_oRightField; } + public function GetOperator() { return $this->m_sOperator; @@ -146,8 +150,9 @@ interface CheckableExpression * @param ModelReflection $oModelReflection MetaModel to consider * @param array $aAliases Aliases to class names (for the current query) * @param string $sSourceQuery For the reporting + * * @throws OqlNormalizeException - */ + */ public function Check(ModelReflection $oModelReflection, $aAliases, $sSourceQuery); } @@ -168,13 +173,11 @@ class MatchOqlExpression extends MatchExpression implements CheckableExpression $this->m_oRightExpr->Check($oModelReflection, $aAliases, $sSourceQuery); // Only field MATCHES scalar is allowed - if (!$this->m_oLeftExpr instanceof FieldExpression) - { + if (!$this->m_oLeftExpr instanceof FieldExpression) { throw new OqlNormalizeException('Only "field MATCHES string" syntax is allowed', $sSourceQuery, new OqlName($this->m_oLeftExpr->RenderExpression(true), 0)); } // Only field MATCHES scalar is allowed - if (!$this->m_oRightExpr instanceof ScalarExpression && !$this->m_oRightExpr instanceof VariableOqlExpression) - { + if (!$this->m_oRightExpr instanceof ScalarExpression && !$this->m_oRightExpr instanceof VariableOqlExpression) { throw new OqlNormalizeException('Only "field MATCHES string" syntax is allowed', $sSourceQuery, new OqlName($this->m_oRightExpr->RenderExpression(true), 0)); } } @@ -198,7 +201,7 @@ class NestedQueryOqlExpression extends NestedQueryExpression implements Checkabl * * @param OQLObjectQuery $oOQLObjectQuery */ - public function __construct($oOQLObjectQuery ) + public function __construct($oOQLObjectQuery) { parent::__construct($oOQLObjectQuery->ToDBSearch("")); $this->m_oOQLObjectQuery = $oOQLObjectQuery; @@ -232,8 +235,7 @@ class FieldOqlExpression extends FieldExpression implements CheckableExpression public function __construct($oName, $oParent = null) { - if (is_null($oParent)) - { + if (is_null($oParent)) { $oParent = new OqlName('', 0); } $this->m_oParent = $oParent; @@ -256,37 +258,28 @@ class FieldOqlExpression extends FieldExpression implements CheckableExpression { $sClassAlias = $this->GetParent(); $sFltCode = $this->GetName(); - if (empty($sClassAlias)) - { + if (empty($sClassAlias)) { // Try to find an alias // Build an array of field => array of aliases $aFieldClasses = array(); - foreach($aAliases as $sAlias => $sReal) - { - foreach($oModelReflection->GetFiltersList($sReal) as $sAnFltCode) - { + foreach ($aAliases as $sAlias => $sReal) { + foreach ($oModelReflection->GetFiltersList($sReal) as $sAnFltCode) { $aFieldClasses[$sAnFltCode][] = $sAlias; } } - if (!array_key_exists($sFltCode, $aFieldClasses)) - { + if (!array_key_exists($sFltCode, $aFieldClasses)) { throw new OqlNormalizeException('Unknown filter code', $sSourceQuery, $this->GetNameDetails(), array_keys($aFieldClasses)); } - if (count($aFieldClasses[$sFltCode]) > 1) - { + if (count($aFieldClasses[$sFltCode]) > 1) { throw new OqlNormalizeException('Ambiguous filter code', $sSourceQuery, $this->GetNameDetails()); } $sClassAlias = $aFieldClasses[$sFltCode][0]; - } - else - { - if (!array_key_exists($sClassAlias, $aAliases)) - { + } else { + if (!array_key_exists($sClassAlias, $aAliases)) { throw new OqlNormalizeException('Unknown class [alias]', $sSourceQuery, $this->GetParentDetails(), array_keys($aAliases)); } $sClass = $aAliases[$sClassAlias]; - if (!$oModelReflection->IsValidFilterCode($sClass, $sFltCode)) - { + if (!$oModelReflection->IsValidFilterCode($sClass, $sFltCode)) { throw new OqlNormalizeException('Unknown filter code', $sSourceQuery, $this->GetNameDetails(), $oModelReflection->GetFiltersList($sClass)); } } @@ -305,8 +298,7 @@ class ListOqlExpression extends ListExpression implements CheckableExpression { public function Check(ModelReflection $oModelReflection, $aAliases, $sSourceQuery) { - foreach ($this->GetItems() as $oItemExpression) - { + foreach ($this->GetItems() as $oItemExpression) { $oItemExpression->Check($oModelReflection, $aAliases, $sSourceQuery); } } @@ -316,8 +308,7 @@ class FunctionOqlExpression extends FunctionExpression implements CheckableExpre { public function Check(ModelReflection $oModelReflection, $aAliases, $sSourceQuery) { - foreach ($this->GetArgs() as $oArgExpression) - { + foreach ($this->GetArgs() as $oArgExpression) { $oArgExpression->Check($oModelReflection, $aAliases, $sSourceQuery); } } @@ -350,6 +341,7 @@ abstract class OqlQuery * Determine the class * * @param ModelReflection $oModelReflection MetaModel to consider + * * @return string * @throws Exception */ @@ -392,6 +384,7 @@ class OqlObjectQuery extends OqlQuery * Determine the class * * @param ModelReflection $oModelReflection MetaModel to consider + * * @return string * @throws Exception */ @@ -415,6 +408,7 @@ class OqlObjectQuery extends OqlQuery { return $this->m_oClass; } + public function GetClassAliasDetails() { return $this->m_oClassAlias; @@ -424,6 +418,7 @@ class OqlObjectQuery extends OqlQuery { return $this->m_aJoins; } + public function GetCondition() { return $this->m_oCondition; @@ -432,44 +427,37 @@ class OqlObjectQuery extends OqlQuery /** * Recursively check the validity of the expression with regard to the data model * and the query in which it is used - * - * @param ModelReflection $oModelReflection MetaModel to consider + * + * @param ModelReflection $oModelReflection MetaModel to consider + * * @throws OqlNormalizeException - */ + */ public function Check(ModelReflection $oModelReflection, $sSourceQuery, $aParentAliases = array()) { $sClass = $this->GetClass($oModelReflection); $sClassAlias = $this->GetClassAlias(); - if (!$oModelReflection->IsValidClass($sClass)) - { + if (!$oModelReflection->IsValidClass($sClass)) { throw new UnknownClassOqlException($sSourceQuery, $this->GetClassDetails(), $oModelReflection->GetClasses()); } - $aAliases = array_merge(array($sClassAlias => $sClass),$aParentAliases); + $aAliases = array_merge(array($sClassAlias => $sClass), $aParentAliases); $aJoinSpecs = $this->GetJoins(); - if (is_array($aJoinSpecs)) - { - foreach ($aJoinSpecs as $oJoinSpec) - { + if (is_array($aJoinSpecs)) { + foreach ($aJoinSpecs as $oJoinSpec) { $sJoinClass = $oJoinSpec->GetClass(); $sJoinClassAlias = $oJoinSpec->GetClassAlias(); - if (!$oModelReflection->IsValidClass($sJoinClass)) - { + if (!$oModelReflection->IsValidClass($sJoinClass)) { throw new UnknownClassOqlException($sSourceQuery, $oJoinSpec->GetClassDetails(), $oModelReflection->GetClasses()); } - if (array_key_exists($sJoinClassAlias, $aAliases)) - { - if ($sJoinClassAlias != $sJoinClass) - { + if (array_key_exists($sJoinClassAlias, $aAliases)) { + if ($sJoinClassAlias != $sJoinClass) { throw new OqlNormalizeException('Duplicate class alias', $sSourceQuery, $oJoinSpec->GetClassAliasDetails()); - } - else - { + } else { throw new OqlNormalizeException('Duplicate class name', $sSourceQuery, $oJoinSpec->GetClassDetails()); } - } + } // Assumption: ext key on the left only !!! // normalization should take care of this @@ -480,85 +468,74 @@ class OqlObjectQuery extends OqlQuery $oRightField = $oJoinSpec->GetRightField(); $sToClass = $oRightField->GetParent(); $sPKeyDescriptor = $oRightField->GetName(); - if ($sPKeyDescriptor != 'id') - { + if ($sPKeyDescriptor != 'id') { throw new OqlNormalizeException('Wrong format for Join clause (right hand), expecting an id', $sSourceQuery, $oRightField->GetNameDetails(), array('id')); } $aAliases[$sJoinClassAlias] = $sJoinClass; - if (!array_key_exists($sFromClass, $aAliases)) - { + if (!array_key_exists($sFromClass, $aAliases)) { throw new OqlNormalizeException('Unknown class in join condition (left expression)', $sSourceQuery, $oLeftField->GetParentDetails(), array_keys($aAliases)); } - if (!array_key_exists($sToClass, $aAliases)) - { + if (!array_key_exists($sToClass, $aAliases)) { throw new OqlNormalizeException('Unknown class in join condition (right expression)', $sSourceQuery, $oRightField->GetParentDetails(), array_keys($aAliases)); } $aExtKeys = $oModelReflection->ListAttributes($aAliases[$sFromClass], \Combodo\iTop\Core\AttributeDefinition\AttributeExternalKey::class); $aObjKeys = $oModelReflection->ListAttributes($aAliases[$sFromClass], \Combodo\iTop\Core\AttributeDefinition\AttributeObjectKey::class); $aAllKeys = array_merge($aExtKeys, $aObjKeys); - if (!array_key_exists($sExtKeyAttCode, $aAllKeys)) - { + if (!array_key_exists($sExtKeyAttCode, $aAllKeys)) { throw new OqlNormalizeException('Unknown key in join condition (left expression)', $sSourceQuery, $oLeftField->GetNameDetails(), array_keys($aAllKeys)); } - if ($sFromClass == $sJoinClassAlias) - { + if ($sFromClass == $sJoinClassAlias) { if (array_key_exists($sExtKeyAttCode, $aExtKeys)) // Skip that check for object keys { $sTargetClass = $oModelReflection->GetAttributeProperty($aAliases[$sFromClass], $sExtKeyAttCode, 'targetclass'); - if(!$oModelReflection->IsSameFamilyBranch($aAliases[$sToClass], $sTargetClass)) - { + if (!$oModelReflection->IsSameFamilyBranch($aAliases[$sToClass], $sTargetClass)) { throw new OqlNormalizeException("The joined class ($aAliases[$sFromClass]) is not compatible with the external key, which is pointing to $sTargetClass", $sSourceQuery, $oLeftField->GetNameDetails()); } } - } - else - { + } else { $sOperator = $oJoinSpec->GetOperator(); - switch($sOperator) - { + switch ($sOperator) { case '=': - $iOperatorCode = TREE_OPERATOR_EQUALS; - break; + $iOperatorCode = TREE_OPERATOR_EQUALS; + break; case 'BELOW': - $iOperatorCode = TREE_OPERATOR_BELOW; - break; + $iOperatorCode = TREE_OPERATOR_BELOW; + break; case 'BELOW_STRICT': - $iOperatorCode = TREE_OPERATOR_BELOW_STRICT; - break; + $iOperatorCode = TREE_OPERATOR_BELOW_STRICT; + break; case 'NOT_BELOW': - $iOperatorCode = TREE_OPERATOR_NOT_BELOW; - break; + $iOperatorCode = TREE_OPERATOR_NOT_BELOW; + break; case 'NOT_BELOW_STRICT': - $iOperatorCode = TREE_OPERATOR_NOT_BELOW_STRICT; - break; + $iOperatorCode = TREE_OPERATOR_NOT_BELOW_STRICT; + break; case 'ABOVE': - $iOperatorCode = TREE_OPERATOR_ABOVE; - break; + $iOperatorCode = TREE_OPERATOR_ABOVE; + break; case 'ABOVE_STRICT': - $iOperatorCode = TREE_OPERATOR_ABOVE_STRICT; - break; + $iOperatorCode = TREE_OPERATOR_ABOVE_STRICT; + break; case 'NOT_ABOVE': - $iOperatorCode = TREE_OPERATOR_NOT_ABOVE; - break; + $iOperatorCode = TREE_OPERATOR_NOT_ABOVE; + break; case 'NOT_ABOVE_STRICT': - $iOperatorCode = TREE_OPERATOR_NOT_ABOVE_STRICT; - break; + $iOperatorCode = TREE_OPERATOR_NOT_ABOVE_STRICT; + break; } if (array_key_exists($sExtKeyAttCode, $aExtKeys)) // Skip that check for object keys { $sTargetClass = $oModelReflection->GetAttributeProperty($aAliases[$sFromClass], $sExtKeyAttCode, 'targetclass'); - if(!$oModelReflection->IsSameFamilyBranch($aAliases[$sToClass], $sTargetClass)) - { + if (!$oModelReflection->IsSameFamilyBranch($aAliases[$sToClass], $sTargetClass)) { throw new OqlNormalizeException("The joined class ($aAliases[$sToClass]) is not compatible with the external key, which is pointing to $sTargetClass", $sSourceQuery, $oLeftField->GetNameDetails()); } } $aAttList = $oModelReflection->ListAttributes($aAliases[$sFromClass]); $sAttType = $aAttList[$sExtKeyAttCode]; - if(($iOperatorCode != TREE_OPERATOR_EQUALS) && !is_subclass_of($sAttType, \Combodo\iTop\Core\AttributeDefinition\AttributeHierarchicalKey::class) && ($sAttType != \Combodo\iTop\Core\AttributeDefinition\AttributeHierarchicalKey::class)) - { + if (($iOperatorCode != TREE_OPERATOR_EQUALS) && !is_a($sAttType, \Combodo\iTop\Core\AttributeDefinition\AttributeHierarchicalKey::class, true)) { throw new OqlNormalizeException("The specified tree operator $sOperator is not applicable to the key", $sSourceQuery, $oLeftField->GetNameDetails()); } } @@ -567,26 +544,23 @@ class OqlObjectQuery extends OqlQuery // Check the select information // - foreach ($this->GetSelectedClasses() as $oClassDetails) - { + foreach ($this->GetSelectedClasses() as $oClassDetails) { $sClassToSelect = $oClassDetails->GetValue(); - if (!array_key_exists($sClassToSelect, $aAliases)) - { + if (!array_key_exists($sClassToSelect, $aAliases)) { throw new OqlNormalizeException('Unknown class [alias]', $sSourceQuery, $oClassDetails, array_keys($aAliases)); } } // Check the condition tree // - if ($this->m_oCondition instanceof Expression) - { + if ($this->m_oCondition instanceof Expression) { $this->m_oCondition->Check($oModelReflection, $aAliases, $sSourceQuery); } } /** * Make the relevant DBSearch instance (FromOQL) - */ + */ public function ToDBSearch($sQuery) { $sClass = $this->GetClass(new ModelReflectionRuntime()); @@ -594,6 +568,7 @@ class OqlObjectQuery extends OqlQuery $oSearch = new DBObjectSearch($sClass, $sClassAlias); $oSearch->InitFromOqlQuery($this, $sQuery); + return $oSearch; } } @@ -606,19 +581,15 @@ class OqlUnionQuery extends OqlQuery { parent::__construct(); $this->aQueries[] = $oLeftQuery; - if ($oRightQueryOrUnion instanceof OqlUnionQuery) - { - foreach ($oRightQueryOrUnion->GetQueries() as $oSingleQuery) - { + if ($oRightQueryOrUnion instanceof OqlUnionQuery) { + foreach ($oRightQueryOrUnion->GetQueries() as $oSingleQuery) { $this->aQueries[] = $oSingleQuery; } - } - else - { + } else { $this->aQueries[] = $oRightQueryOrUnion; } } - + public function GetQueries() { return $this->aQueries; @@ -627,66 +598,54 @@ class OqlUnionQuery extends OqlQuery /** * Check the validity of the expression with regard to the data model * and the query in which it is used - * - * @param ModelReflection $oModelReflection MetaModel to consider + * + * @param ModelReflection $oModelReflection MetaModel to consider + * * @throws OqlNormalizeException - */ + */ public function Check(ModelReflection $oModelReflection, $sSourceQuery) { $aColumnToClasses = array(); - foreach ($this->aQueries as $iQuery => $oQuery) - { + foreach ($this->aQueries as $iQuery => $oQuery) { $oQuery->Check($oModelReflection, $sSourceQuery); $aAliasToClass = array($oQuery->GetClassAlias() => $oQuery->GetClass($oModelReflection)); $aJoinSpecs = $oQuery->GetJoins(); - if (is_array($aJoinSpecs)) - { - foreach ($aJoinSpecs as $oJoinSpec) - { + if (is_array($aJoinSpecs)) { + foreach ($aJoinSpecs as $oJoinSpec) { $aAliasToClass[$oJoinSpec->GetClassAlias()] = $oJoinSpec->GetClass(); } } $aSelectedClasses = $oQuery->GetSelectedClasses(); - if ($iQuery != 0) - { - if (count($aSelectedClasses) < count($aColumnToClasses)) - { + if ($iQuery != 0) { + if (count($aSelectedClasses) < count($aColumnToClasses)) { $oLastClass = end($aSelectedClasses); throw new OqlNormalizeException('Too few selected classes in the subquery', $sSourceQuery, $oLastClass); } - if (count($aSelectedClasses) > count($aColumnToClasses)) - { + if (count($aSelectedClasses) > count($aColumnToClasses)) { $oLastClass = end($aSelectedClasses); throw new OqlNormalizeException('Too many selected classes in the subquery', $sSourceQuery, $oLastClass); } } - foreach ($aSelectedClasses as $iColumn => $oClassDetails) - { + foreach ($aSelectedClasses as $iColumn => $oClassDetails) { $sAlias = $oClassDetails->GetValue(); $sClass = $aAliasToClass[$sAlias]; $aColumnToClasses[$iColumn][] = array( - 'alias' => $sAlias, - 'class' => $sClass, + 'alias' => $sAlias, + 'class' => $sClass, 'class_name' => $oClassDetails, ); } } - foreach ($aColumnToClasses as $iColumn => $aClasses) - { + foreach ($aColumnToClasses as $iColumn => $aClasses) { $sRootClass = null; - foreach ($aClasses as $iQuery => $aData) - { - if ($iQuery == 0) - { + foreach ($aClasses as $iQuery => $aData) { + if ($iQuery == 0) { // Establish the reference $sRootClass = $oModelReflection->GetRootClass($aData['class']); - } - else - { - if ($oModelReflection->GetRootClass($aData['class']) != $sRootClass) - { + } else { + if ($oModelReflection->GetRootClass($aData['class']) != $sRootClass) { $aSubclasses = $oModelReflection->EnumChildClasses($sRootClass, ENUM_CHILD_CLASSES_ALL); throw new OqlNormalizeException('Incompatible classes: could not find a common ancestor', $sSourceQuery, $aData['class_name'], $aSubclasses); } @@ -699,21 +658,21 @@ class OqlUnionQuery extends OqlQuery * Determine the class * * @param ModelReflection $oModelReflection MetaModel to consider + * * @return string * @throws Exception */ public function GetClass(ModelReflection $oModelReflection) { $aFirstColClasses = array(); - foreach ($this->aQueries as $iQuery => $oQuery) - { + foreach ($this->aQueries as $iQuery => $oQuery) { $aFirstColClasses[] = $oQuery->GetClass($oModelReflection); } $sClass = self::GetLowestCommonAncestor($oModelReflection, $aFirstColClasses); - if (is_null($sClass)) - { + if (is_null($sClass)) { throw new Exception('Could not determine the class of the union query. This issue should have been detected earlier by calling OqlQuery::Check()'); } + return $sClass; } @@ -726,6 +685,7 @@ class OqlUnionQuery extends OqlQuery public function GetClassAlias() { $sAlias = $this->aQueries[0]->GetClassAlias(); + return $sAlias; } @@ -735,29 +695,25 @@ class OqlUnionQuery extends OqlQuery * * @param ModelReflection $oModelReflection MetaModel to consider * @param array $aClasses Flat list of classes + * * @return string the lowest common ancestor amongst classes, null if none has been found * @throws Exception */ public static function GetLowestCommonAncestor(ModelReflection $oModelReflection, $aClasses) { $sAncestor = null; - foreach($aClasses as $sClass) - { - if (is_null($sAncestor)) - { + foreach ($aClasses as $sClass) { + if (is_null($sAncestor)) { // first loop $sAncestor = $sClass; - } - elseif ($oModelReflection->GetRootClass($sClass) != $oModelReflection->GetRootClass($sAncestor)) - { + } elseif ($oModelReflection->GetRootClass($sClass) != $oModelReflection->GetRootClass($sAncestor)) { $sAncestor = null; break; - } - else - { + } else { $sAncestor = self::LowestCommonAncestor($oModelReflection, $sAncestor, $sClass); } } + return $sAncestor; } @@ -766,37 +722,32 @@ class OqlUnionQuery extends OqlQuery */ protected static function LowestCommonAncestor(ModelReflection $oModelReflection, $sClassA, $sClassB) { - if ($sClassA == $sClassB) - { + if ($sClassA == $sClassB) { $sRet = $sClassA; - } - elseif (in_array($sClassA, $oModelReflection->EnumChildClasses($sClassB))) - { + } elseif (in_array($sClassA, $oModelReflection->EnumChildClasses($sClassB))) { $sRet = $sClassB; - } - elseif (in_array($sClassB, $oModelReflection->EnumChildClasses($sClassA))) - { + } elseif (in_array($sClassB, $oModelReflection->EnumChildClasses($sClassA))) { $sRet = $sClassA; - } - else - { + } else { // Recurse $sRet = self::LowestCommonAncestor($oModelReflection, $sClassA, $oModelReflection->GetParentClass($sClassB)); } + return $sRet; } + /** * Make the relevant DBSearch instance (FromOQL) - */ + */ public function ToDBSearch($sQuery) { $aSearches = array(); - foreach ($this->aQueries as $oQuery) - { + foreach ($this->aQueries as $oQuery) { $aSearches[] = $oQuery->ToDBSearch($sQuery); } $oSearch = new DBUnionSearch($aSearches); + return $oSearch; } } diff --git a/core/ormcaselog.class.inc.php b/core/ormcaselog.class.inc.php index f820f1d2f..fdfefc8a3 100644 --- a/core/ormcaselog.class.inc.php +++ b/core/ormcaselog.class.inc.php @@ -370,7 +370,7 @@ class ormCaseLog /** * Produces an HTML representation, aimed at being used within the iTop framework */ - public function GetAsHTML(WebPage $oP = null, $bEditMode = false, $aTransfoHandler = null) + public function GetAsHTML(?WebPage $oP = null, $bEditMode = false, $aTransfoHandler = null) { $bPrintableVersion = (utils::ReadParam('printable', '0') == '1'); diff --git a/core/ormdocument.class.inc.php b/core/ormdocument.class.inc.php index 56618dcaf..3efe00dbd 100644 --- a/core/ormdocument.class.inc.php +++ b/core/ormdocument.class.inc.php @@ -362,8 +362,7 @@ class ormDocument throw new Exception("Invalid id ($id) for class '$sClass' - the object does not exist or you are not allowed to view it"); } } - if (($sSecretField != null) && ($oObj->Get($sSecretField) != $sSecretValue)) { - usleep(200); + if (($sSecretField != null) && !hash_equals($oObj->Get($sSecretField), $sSecretValue)) { throw new Exception("Invalid secret for class '$sClass' - the object does not exist or you are not allowed to view it"); } /** @var \ormDocument $oDocument */ diff --git a/core/ormlinkset.class.inc.php b/core/ormlinkset.class.inc.php index 56573dc51..3e7f80771 100644 --- a/core/ormlinkset.class.inc.php +++ b/core/ormlinkset.class.inc.php @@ -93,7 +93,7 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator * @param DBObjectSet|null $oOriginalSet * @throws Exception */ - public function __construct($sHostClass, $sAttCode, DBObjectSet $oOriginalSet = null) + public function __construct($sHostClass, $sAttCode, ?DBObjectSet $oOriginalSet = null) { $this->sHostClass = $sHostClass; $this->sAttCode = $sAttCode; diff --git a/core/ormpassword.class.inc.php b/core/ormpassword.class.inc.php index f8b4d2122..9167c1b1a 100644 --- a/core/ormpassword.class.inc.php +++ b/core/ormpassword.class.inc.php @@ -98,9 +98,9 @@ class ormPassword $bResult = false; $aInfo = password_get_info($this->m_sHashed); if (is_null($aInfo["algo"]) || $aInfo["algo"] === 0) { - //unknown, assume it's a legacy password + // - Unknown algorithm, assume it's a legacy password $sHashedPwd = $this->ComputeHash($sClearTextPassword); - $bResult = ($this->m_sHashed == $sHashedPwd); + $bResult = hash_equals($this->m_sHashed, $sHashedPwd); } else { $bResult = password_verify($sClearTextPassword, $this->m_sHashed); } diff --git a/core/userrights.class.inc.php b/core/userrights.class.inc.php index 118f19b39..f86a15a49 100644 --- a/core/userrights.class.inc.php +++ b/core/userrights.class.inc.php @@ -415,12 +415,7 @@ abstract class User extends cmdbAbstractObject $this->m_aCheckIssues[] = Dict::S('Class:User/Error:CurrentProfilesHaveInsufficientRights'); } $oAddon->ResetCache(); - - if (is_null($aCurrentProfiles)) { - Session::IsSet('profile_list'); - } else { - Session::Set('profile_list', $aCurrentProfiles); - } + Session::Set('profile_list', $aCurrentProfiles); } // Prevent an administrator to remove their own admin profile if (UserRights::IsAdministrator($this)) { diff --git a/css/backoffice/application/bulk/_all.scss b/css/backoffice/application/bulk/_all.scss index 495ed376f..fcd615d40 100644 --- a/css/backoffice/application/bulk/_all.scss +++ b/css/backoffice/application/bulk/_all.scss @@ -4,3 +4,4 @@ */ @import "bulk-modify"; +@import "bulk-export"; diff --git a/css/backoffice/application/bulk/_bulk-export.scss b/css/backoffice/application/bulk/_bulk-export.scss new file mode 100644 index 000000000..b595b6c82 --- /dev/null +++ b/css/backoffice/application/bulk/_bulk-export.scss @@ -0,0 +1,10 @@ +/* + * @copyright Copyright (C) 2010-2026 Combodo SAS + * @license http://opensource.org/licenses/AGPL-3.0 + */ + +#form_part_csv_options:has(#ibo-sanitize-excel-export--input:checked), #form_part_xlsx_options:has(#ibo-sanitize-excel-export--input:checked){ + #ibo-sanitize-excel-export--alert { + display: none; + } +} \ No newline at end of file diff --git a/css/backoffice/blocks-integrations/field/_field-with-field.scss b/css/backoffice/blocks-integrations/field/_field-with-field.scss index fb2d7ea3e..73709adbe 100644 --- a/css/backoffice/blocks-integrations/field/_field-with-field.scss +++ b/css/backoffice/blocks-integrations/field/_field-with-field.scss @@ -4,7 +4,7 @@ */ $ibo-field--spacing-top--with-same-block: $ibo-spacing-500 !default; -.ibo-field + .ibo-field { +.ibo-field + .ibo-field:not(:empty) { margin-top: $ibo-field--spacing-top--with-same-block; } diff --git a/css/backoffice/components/_form.scss b/css/backoffice/components/_form.scss index d80fdd96a..c732bebd8 100644 --- a/css/backoffice/components/_form.scss +++ b/css/backoffice/components/_form.scss @@ -6,4 +6,72 @@ .ibo-prop-header { @extend %ibo-font-size-150; padding-bottom: 14px; -} \ No newline at end of file +} + +.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: .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{ + margin-right: 5px; +} + +.ibo-form textarea{ + resize: vertical; +} + diff --git a/css/backoffice/components/_panel.scss b/css/backoffice/components/_panel.scss index 0924a3237..134d5ba21 100644 --- a/css/backoffice/components/_panel.scss +++ b/css/backoffice/components/_panel.scss @@ -72,9 +72,12 @@ $ibo-panel--icon--spacing--as-medallion--is-sticking: $ibo-panel--icon--spacing- $ibo-panel--icon--bottom--as-medallion--is-sticking: -12px !default; $ibo-panel--icon--border--as-medallion--is-sticking: 1px $ibo-panel--base-border-style $ibo-panel--base-border-color !default; -$ibo-panel--icon-background--size--must-contain: contain !default; -$ibo-panel--icon-background--size--must-cover: cover !default; -$ibo-panel--icon-background--size--must-zoomout: 66.67% !default; +$ibo-panel--icon-background--size--must-contain: contain !default; // deprecated, to be removed in favor of $ibo-panel--icon-img--size--must-contain +$ibo-panel--icon-background--size--must-cover: cover !default; // deprecated, to be removed in favor of $ibo-panel--icon-img--size--must-cover +$ibo-panel--icon-background--size--must-zoomout: 66.67% !default; // deprecated, to be removed in favor of $ibo-panel--icon-img--size--must-zoomout +$ibo-panel--icon-img--size--must-contain: $ibo-panel--icon-background--size--must-contain !default; // TODO remove when dealing with N°9317 +$ibo-panel--icon-img--size--must-cover: $ibo-panel--icon-background--size--must-cover !default; // TODO remove when dealing with N°9317 +$ibo-panel--icon-img--size--must-zoomout: $ibo-panel--icon-background--size--must-zoomout !default; // TODO remove when dealing with N°9317 $ibo-panel--title--font-size--is-sticking: $ibo-font-size-150 !default; $ibo-panel--title--color: $ibo-color-grey-900 !default; @@ -179,24 +182,25 @@ $ibo-panel--is-selectable--body--after--font-size: $ibo-font-size-700 !default; min-height: $ibo-panel--icon--size; } -.ibo-panel--icon-background { +.ibo-panel--icon-img, .ibo-panel--icon-background { // second class is deprecated, remove it when dealing with N°9317 width: 100%; height: 100%; background-position: center; background-repeat: no-repeat; - background-size: $ibo-panel--icon-background--size--must-contain; + background-size: $ibo-panel--icon-img--size--must-contain; } -.ibo-panel--icon-background--must-contain { - background-size: $ibo-panel--icon-background--size--must-contain; +.ibo-panel--icon-img--must-contain, .ibo-panel--icon-background--must-contain { // second class is deprecated, remove it when dealing with N°9317 + background-size: $ibo-panel--icon-img--size--must-contain; } -.ibo-panel--icon-background--must-cover { - background-size: $ibo-panel--icon-background--size--must-cover; +.ibo-panel--icon-img--must-cover, .ibo-panel--icon-background--must-cover { // second class is deprecated, remove it when dealing with N°9317 + background-size: $ibo-panel--icon-img--size--must-cover; } -.ibo-panel--icon-background--must-zoomout { - background-size: $ibo-panel--icon-background--size--must-zoomout; +.ibo-panel--icon-img--must-zoomout, .ibo-panel--icon-background--must-zoomout { // second class is deprecated, remove it when dealing with N°9317 + width: $ibo-panel--icon-img--size--must-zoomout; + height: $ibo-panel--icon-img--size--must-zoomout; } .ibo-panel--title { diff --git a/css/backoffice/components/_title.scss b/css/backoffice/components/_title.scss index c513016c1..d430d90c2 100644 --- a/css/backoffice/components/_title.scss +++ b/css/backoffice/components/_title.scss @@ -11,9 +11,12 @@ $ibo-title--icon--size: 90px !default; $ibo-title--icon--size-2: 80px !default; $ibo-title--icon--size-3: 70px !default; -$ibo-title--icon-background--size--must-contain: contain !default; -$ibo-title--icon-background--size--must-cover: cover !default; -$ibo-title--icon-background--size--must-zoomout: 66.67% !default; +$ibo-title--icon-background--size--must-contain: contain !default; // deprecated, to be removed in favor of $ibo-title--icon-img--size--must-contain +$ibo-title--icon-background--size--must-cover: cover !default; // deprecated, to be removed in favor of $ibo-title--icon-img--size--must-cover +$ibo-title--icon-background--size--must-zoomout: 66.67% !default; // deprecated, to be removed in favor of $ibo-title--icon-img--size--must-zoomout +$ibo-title--icon-img--size--must-contain: $ibo-title--icon-background--size--must-contain !default; // TODO remove when dealing with N°9317 +$ibo-title--icon-img--size--must-cover: $ibo-title--icon-background--size--must-cover !default; // TODO remove when dealing with N°9317 +$ibo-title--icon-img--size--must-zoomout: $ibo-title--icon-background--size--must-zoomout !default; // TODO remove when dealing with N°9317 .ibo-title { @@ -44,24 +47,23 @@ $ibo-title--icon-background--size--must-zoomout: 66.67% !default; min-height: $ibo-title--icon--size-3; } -.ibo-title--icon-background { +.ibo-title--icon-img, .ibo-title--icon-background { // second class is deprecated, remove it when dealing with N°9317 width: 100%; height: 100%; - background-position: center; - background-repeat: no-repeat; - background-size: $ibo-title--icon-background--size--must-contain; + object-position: center; + background-size: $ibo-title--icon-img--size--must-contain; } -.ibo-title--icon-background--must-contain { - background-size: $ibo-title--icon-background--size--must-contain; +.ibo-title--icon-img--must-contain, .ibo-title--icon-background--must-contain { // second class is deprecated, remove it when dealing with N°9317 + background-size: $ibo-title--icon-img--size--must-contain; } -.ibo-title--icon-background--must-cover { - background-size: $ibo-title--icon-background--size--must-cover; +.ibo-title--icon-img--must-cover, .ibo-title--icon-background--must-cover { // second class is deprecated, remove it when dealing with N°9317 + background-size: $ibo-title--icon-img--size--must-cover; } -.ibo-title--icon-background--must-zoomout { - background-size: $ibo-title--icon-background--size--must-zoomout; +.ibo-title--icon-img--must-zoomout, .ibo-title--icon-background--must-zoomout { // second class is deprecated, remove it when dealing with N°9317 + background-size: $ibo-title--icon-img--size--must-zoomout; } .ibo-title--for-object-details { diff --git a/css/backoffice/layout/multi-column/_multi-column.scss b/css/backoffice/layout/multi-column/_multi-column.scss index 75d495047..7a11b5559 100644 --- a/css/backoffice/layout/multi-column/_multi-column.scss +++ b/css/backoffice/layout/multi-column/_multi-column.scss @@ -5,9 +5,11 @@ $ibo-multi-column--margin-x: -$ibo-spacing-500 !default; /* This is to compensate columns padding and make the whole multicolumn align with the parent borders (cf. Bootstrap rows / cols) */ $ibo-multi-column--margin-y: $ibo-spacing-0 !default; +$ibo-multi-column--row-gap: $ibo-spacing-800 !default; .ibo-multi-column { display: flex; flex-wrap: wrap; margin: $ibo-multi-column--margin-y $ibo-multi-column--margin-x; + row-gap: $ibo-multi-column--row-gap; } \ No newline at end of file diff --git a/css/backoffice/vendors/_selectize.scss b/css/backoffice/vendors/_selectize.scss index 67c5b834a..088eeb062 100644 --- a/css/backoffice/vendors/_selectize.scss +++ b/css/backoffice/vendors/_selectize.scss @@ -29,7 +29,7 @@ $ibo-vendors-selectize--element--active--background: $ibo-color-blue-100 !defaul $ibo-vendors-selectize--element--active--color: $ibo-color-grey-900 !default; $ibo-vendors-selectize--dropdown--background-color: $ibo-vendors-selectize-input--background-color !default; -$ibo-vendors-selectize--dropdown--color: $ibo-vendors-selectize-input--color!default; +$ibo-vendors-selectize--dropdown--color: $ibo-vendors-selectize-input--color !default; $ibo-vendors-selectize--header--padding-x: 8px !default; $ibo-vendors-selectize--header--padding-y: 5px !default; diff --git a/css/backoffice/vendors/_tomselect.scss b/css/backoffice/vendors/_tomselect.scss new file mode 100644 index 000000000..74cdeddf2 --- /dev/null +++ b/css/backoffice/vendors/_tomselect.scss @@ -0,0 +1,3 @@ +@import "../../../node_modules/tom-select/dist/scss/tom-select.scss"; + +$select-color-item-active-border: $ibo-input--focus--border-color; \ No newline at end of file diff --git a/data/.compilation-symlinks b/data/.compilation-symlinks new file mode 100644 index 000000000..e69de29bb diff --git a/datamodels/2.x/authent-local/datamodel.authent-local.xml b/datamodels/2.x/authent-local/datamodel.authent-local.xml index be5c5fb59..bbceb0624 100644 --- a/datamodels/2.x/authent-local/datamodel.authent-local.xml +++ b/datamodels/2.x/authent-local/datamodel.authent-local.xml @@ -2,7 +2,7 @@ - ^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^\da-zA-Z]).{8,}$ + ^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^\da-zA-Z]).{12,}$ diff --git a/datamodels/2.x/authent-local/dictionaries/cs.dict.authent-local.php b/datamodels/2.x/authent-local/dictionaries/cs.dict.authent-local.php index 7f1c83b66..06f31e275 100644 --- a/datamodels/2.x/authent-local/dictionaries/cs.dict.authent-local.php +++ b/datamodels/2.x/authent-local/dictionaries/cs.dict.authent-local.php @@ -29,7 +29,7 @@ Dict::Add('CS CZ', 'Czech', 'Čeština', [ 'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'Heslo nemůže uživatel změnit.', 'Class:UserLocal/Attribute:password_renewed_date' => 'Heslo bylo obnoveno', 'Class:UserLocal/Attribute:password_renewed_date+' => 'Termín, kdy bylo heslo změneno', - 'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Heslo musí obsahovat minimálně 8 znaků a musí obsahovat minimálně jedno velké písmeno, jedno malé písmeno, jedno číslo a speciální znak.', + 'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Heslo musí obsahovat minimálně 12 znaků a musí obsahovat minimálně jedno velké písmeno, jedno malé písmeno, jedno číslo a speciální znak.', 'UserLocal:password:expiration' => 'Níže uvedená pole vyžadují rozšíření', 'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Nastavení exspirace "Jednorázového hesla" nelze u vlastního účtu uživatele.', ]); diff --git a/datamodels/2.x/authent-local/dictionaries/da.dict.authent-local.php b/datamodels/2.x/authent-local/dictionaries/da.dict.authent-local.php index 79c5c7339..b4fad86aa 100644 --- a/datamodels/2.x/authent-local/dictionaries/da.dict.authent-local.php +++ b/datamodels/2.x/authent-local/dictionaries/da.dict.authent-local.php @@ -28,7 +28,7 @@ Dict::Add('DA DA', 'Danish', 'Dansk', [ 'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'Password cannot be changed by the user.~~', 'Class:UserLocal/Attribute:password_renewed_date' => 'Password renewed on~~', 'Class:UserLocal/Attribute:password_renewed_date+' => 'When the password was last changed~~', - 'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 8 characters and include uppercase, lowercase, numeric and special characters.~~', + 'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 12 characters and include uppercase, lowercase, numeric and special characters.~~', 'UserLocal:password:expiration' => 'The fields below require an extension~~', 'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Setting password expiration to "One-time password" is not allowed for your own User~~', ]); diff --git a/datamodels/2.x/authent-local/dictionaries/de.dict.authent-local.php b/datamodels/2.x/authent-local/dictionaries/de.dict.authent-local.php index 269105507..a3822ccb2 100644 --- a/datamodels/2.x/authent-local/dictionaries/de.dict.authent-local.php +++ b/datamodels/2.x/authent-local/dictionaries/de.dict.authent-local.php @@ -28,7 +28,7 @@ Dict::Add('DE DE', 'German', 'Deutsch', [ 'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => '', 'Class:UserLocal/Attribute:password_renewed_date' => 'Letzte Passworterneuerung', 'Class:UserLocal/Attribute:password_renewed_date+' => 'Letztes Änderungsdatum', - 'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Das Passwort entspricht nicht dem in den Konfigurationsregeln hinterlegten RegEx-Ausdruck', + 'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Das Passwort muss mindestens 12 Zeichen lang sein und Großbuchstaben, Kleinbuchstaben, Zahlen und Sonderzeichen enthalten.', 'UserLocal:password:expiration' => 'Die folgenden Felder benötigen eine '.ITOP_APPLICATION_SHORT.' Erweiterung', 'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Das setzen des Passwortablaufs auf "Einmalpasswort" ist für den eigenen Benutzer nicht erlaubt.', ]); diff --git a/datamodels/2.x/authent-local/dictionaries/en.dict.authent-local.php b/datamodels/2.x/authent-local/dictionaries/en.dict.authent-local.php index 1e588bd5e..afeb56a2f 100644 --- a/datamodels/2.x/authent-local/dictionaries/en.dict.authent-local.php +++ b/datamodels/2.x/authent-local/dictionaries/en.dict.authent-local.php @@ -55,7 +55,7 @@ Dict::Add('EN US', 'English', 'English', [ 'Class:UserLocal/Attribute:password_renewed_date' => 'Password renewed on', 'Class:UserLocal/Attribute:password_renewed_date+' => 'When the password was last changed', - 'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 8 characters and include uppercase, lowercase, numeric and special characters.', + 'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 12 characters and include uppercase, lowercase, numeric and special characters.', 'UserLocal:password:expiration' => 'The fields below require an extension', 'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Setting password expiration to "One-time password" is not allowed for your own User', ]); diff --git a/datamodels/2.x/authent-local/dictionaries/en_gb.dict.authent-local.php b/datamodels/2.x/authent-local/dictionaries/en_gb.dict.authent-local.php index bc57f4b4e..017256823 100644 --- a/datamodels/2.x/authent-local/dictionaries/en_gb.dict.authent-local.php +++ b/datamodels/2.x/authent-local/dictionaries/en_gb.dict.authent-local.php @@ -55,7 +55,7 @@ Dict::Add('EN GB', 'British English', 'British English', [ 'Class:UserLocal/Attribute:password_renewed_date' => 'Password renewed on', 'Class:UserLocal/Attribute:password_renewed_date+' => 'When the password was last changed', - 'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 8 characters and include uppercase, lowercase, numeric and special characters.', + 'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 12 characters and include uppercase, lowercase, numeric and special characters.', 'UserLocal:password:expiration' => 'The fields below require an extension', 'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Setting password expiration to "One-time password" is not allowed for your own User', ]); diff --git a/datamodels/2.x/authent-local/dictionaries/es_cr.dict.authent-local.php b/datamodels/2.x/authent-local/dictionaries/es_cr.dict.authent-local.php index adda854d0..4841a3402 100644 --- a/datamodels/2.x/authent-local/dictionaries/es_cr.dict.authent-local.php +++ b/datamodels/2.x/authent-local/dictionaries/es_cr.dict.authent-local.php @@ -25,7 +25,7 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', [ 'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'El usuario no puede cambiar la contraseña.', 'Class:UserLocal/Attribute:password_renewed_date' => 'Renovación de contraseña', 'Class:UserLocal/Attribute:password_renewed_date+' => 'Cuando fue el último cambio de contraseña', - 'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'La contraseña debe ser de al menos 8 caracteres e incluír mayúsculas, minúsculas, números y caracteres especiales.', + 'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'La contraseña debe ser de al menos 12 caracteres e incluir mayúsculas, minúsculas, números y caracteres especiales.', 'UserLocal:password:expiration' => 'El siguiente campo requiere una extensión', 'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Configurar expiración de contraseña para "ontraseña de un solo uso" no está permitido para su propio Usuario', ]); diff --git a/datamodels/2.x/authent-local/dictionaries/fr.dict.authent-local.php b/datamodels/2.x/authent-local/dictionaries/fr.dict.authent-local.php index 12727a746..4686cd9ef 100644 --- a/datamodels/2.x/authent-local/dictionaries/fr.dict.authent-local.php +++ b/datamodels/2.x/authent-local/dictionaries/fr.dict.authent-local.php @@ -27,7 +27,7 @@ Dict::Add('FR FR', 'French', 'Français', [ 'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => '', 'Class:UserLocal/Attribute:password_renewed_date' => 'Mot de passe changé le', 'Class:UserLocal/Attribute:password_renewed_date+' => 'Dernière date à laquelle le mot de passe a été changé', - 'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Le mot de passe doit contenir au moins 8 caractères, avec minuscule, majuscule, nombre et caractère spécial.', + 'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Le mot de passe doit contenir au moins 12 caractères, avec minuscule, majuscule, nombre et caractère spécial.', 'UserLocal:password:expiration' => 'Les champs ci-dessous nécessitent une extension', 'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Impossible de mettre "Usage unique" comme validité du mot de passe pour son propre utilisateur.', ]); diff --git a/datamodels/2.x/authent-local/dictionaries/hu.dict.authent-local.php b/datamodels/2.x/authent-local/dictionaries/hu.dict.authent-local.php index 270ece0e4..1090d7119 100644 --- a/datamodels/2.x/authent-local/dictionaries/hu.dict.authent-local.php +++ b/datamodels/2.x/authent-local/dictionaries/hu.dict.authent-local.php @@ -27,7 +27,7 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', [ 'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'A felhasználó nem változtathat jelszót.', 'Class:UserLocal/Attribute:password_renewed_date' => 'Jelszó megújítás ideje', 'Class:UserLocal/Attribute:password_renewed_date+' => 'A jelszó legutóbbi módosításának időpontja', - 'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'A jelszónak legalább 8 karakterből kell állnia, és tartalmaznia kell nagybetűket, kisbetűket, numerikus és speciális karaktereket.', + 'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'A jelszónak legalább 12 karakterből kell állnia, és tartalmaznia kell nagybetűket, kisbetűket, numerikus és speciális karaktereket.', 'UserLocal:password:expiration' => 'Az alábbi mezőkhöz egy bővítmény szükséges', 'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'A jelszó lejárati idejének beállítása "Egyszeri jelszóra" nem engedélyezett a saját Felhasználó számára.', ]); diff --git a/datamodels/2.x/authent-local/dictionaries/it.dict.authent-local.php b/datamodels/2.x/authent-local/dictionaries/it.dict.authent-local.php index 3bfd3414c..ee50fa086 100644 --- a/datamodels/2.x/authent-local/dictionaries/it.dict.authent-local.php +++ b/datamodels/2.x/authent-local/dictionaries/it.dict.authent-local.php @@ -27,7 +27,7 @@ Dict::Add('IT IT', 'Italian', 'Italiano', [ 'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'La password non può essere cambiata dall\'utente.', 'Class:UserLocal/Attribute:password_renewed_date' => 'Rinnovo della password', 'Class:UserLocal/Attribute:password_renewed_date+' => 'Quando è stata cambiata l\'ultima volta la password', - 'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'La password deve essere di almeno 8 caratteri e includere lettere maiuscole, minuscole, numeri e caratteri speciali.', + 'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'La password deve essere di almeno 12 caratteri e includere lettere maiuscole, minuscole, numeri e caratteri speciali.', 'UserLocal:password:expiration' => 'I campi sottostanti richiedono un\'estensione', 'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Impostare la scadenza della password su "Password monouso" non è consentito per il proprio utente', ]); diff --git a/datamodels/2.x/authent-local/dictionaries/ja.dict.authent-local.php b/datamodels/2.x/authent-local/dictionaries/ja.dict.authent-local.php index bc47d26b3..69b6b519b 100644 --- a/datamodels/2.x/authent-local/dictionaries/ja.dict.authent-local.php +++ b/datamodels/2.x/authent-local/dictionaries/ja.dict.authent-local.php @@ -28,7 +28,7 @@ Dict::Add('JA JP', 'Japanese', '日本語', [ 'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'Password cannot be changed by the user.~~', 'Class:UserLocal/Attribute:password_renewed_date' => 'Password renewed on~~', 'Class:UserLocal/Attribute:password_renewed_date+' => 'When the password was last changed~~', - 'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 8 characters and include uppercase, lowercase, numeric and special characters.~~', + 'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 12 characters and include uppercase, lowercase, numeric and special characters.~~', 'UserLocal:password:expiration' => 'The fields below require an extension~~', 'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Setting password expiration to "One-time password" is not allowed for your own User~~', ]); diff --git a/datamodels/2.x/authent-local/dictionaries/nl.dict.authent-local.php b/datamodels/2.x/authent-local/dictionaries/nl.dict.authent-local.php index 71a666179..493c36746 100644 --- a/datamodels/2.x/authent-local/dictionaries/nl.dict.authent-local.php +++ b/datamodels/2.x/authent-local/dictionaries/nl.dict.authent-local.php @@ -28,7 +28,7 @@ Dict::Add('NL NL', 'Dutch', 'Nederlands', [ 'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'De gebruiker kan dit wachtwoord niet veranderen.', 'Class:UserLocal/Attribute:password_renewed_date' => 'Wachtwoord laatst aangepast', 'Class:UserLocal/Attribute:password_renewed_date+' => 'Tijdstip waarop het wachtwoord het laatst aangepast werd.', - 'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Het wachtwoord bestaat uit minstens 8 tekens en bestaat uit een mix van minstens 1 hoofdletter, kleine letter, cijfer en speciaal teken.', + 'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Het wachtwoord bestaat uit minstens 12 tekens en bestaat uit een mix van minstens 1 hoofdletter, kleine letter, cijfer en speciaal teken.', 'UserLocal:password:expiration' => 'De velden hieronder vereisen een extensie.', 'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Je kan geen eenmalig wachtwoord instellen voor je eigen gebruiker.', ]); diff --git a/datamodels/2.x/authent-local/dictionaries/pl.dict.authent-local.php b/datamodels/2.x/authent-local/dictionaries/pl.dict.authent-local.php index e671940ee..1d600c987 100644 --- a/datamodels/2.x/authent-local/dictionaries/pl.dict.authent-local.php +++ b/datamodels/2.x/authent-local/dictionaries/pl.dict.authent-local.php @@ -27,7 +27,7 @@ Dict::Add('PL PL', 'Polish', 'Polski', [ 'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'Hasło nie może być zmienione przez użytkownika.', 'Class:UserLocal/Attribute:password_renewed_date' => 'Odnowienie hasła', 'Class:UserLocal/Attribute:password_renewed_date+' => 'Kiedy ostatnio zmieniano hasło', - 'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Hasło musi mieć co najmniej 8 znaków i zawierać duże, małe litery, cyfry i znaki specjalne.', + 'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Hasło musi mieć co najmniej 12 znaków i zawierać duże, małe litery, cyfry i znaki specjalne.', 'UserLocal:password:expiration' => 'Poniższe pola wymagają rozszerzenia', 'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Ustawienie wygaśnięcia hasła "Hasło jednorazowe" nie jest dozwolone dla własnego użytkownika', ]); diff --git a/datamodels/2.x/authent-local/dictionaries/ru.dict.authent-local.php b/datamodels/2.x/authent-local/dictionaries/ru.dict.authent-local.php index 94b55aa42..c8ae6c4a6 100644 --- a/datamodels/2.x/authent-local/dictionaries/ru.dict.authent-local.php +++ b/datamodels/2.x/authent-local/dictionaries/ru.dict.authent-local.php @@ -28,7 +28,7 @@ Dict::Add('RU RU', 'Russian', 'Русский', [ 'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'Password cannot be changed by the user.~~', 'Class:UserLocal/Attribute:password_renewed_date' => 'Дата изменения пароля', 'Class:UserLocal/Attribute:password_renewed_date+' => 'Когда пароль был изменен в последний раз', - 'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Пароль должен содержать не менее 8 символов и включать прописные, строчные, числовые и специальные символы.', + 'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Пароль должен содержать не менее 12 символов и включать прописные, строчные, числовые и специальные символы.', 'UserLocal:password:expiration' => 'Поля требуют наличия доп. расширения', 'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Setting password expiration to "One-time password" is not allowed for your own User~~', ]); diff --git a/datamodels/2.x/authent-local/dictionaries/sk.dict.authent-local.php b/datamodels/2.x/authent-local/dictionaries/sk.dict.authent-local.php index 4042476a3..60cc39073 100644 --- a/datamodels/2.x/authent-local/dictionaries/sk.dict.authent-local.php +++ b/datamodels/2.x/authent-local/dictionaries/sk.dict.authent-local.php @@ -27,7 +27,7 @@ Dict::Add('SK SK', 'Slovak', 'Slovenčina', [ 'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'Password cannot be changed by the user.~~', 'Class:UserLocal/Attribute:password_renewed_date' => 'Password renewed on~~', 'Class:UserLocal/Attribute:password_renewed_date+' => 'When the password was last changed~~', - 'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 8 characters and include uppercase, lowercase, numeric and special characters.~~', + 'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 12 characters and include uppercase, lowercase, numeric and special characters.~~', 'UserLocal:password:expiration' => 'The fields below require an extension~~', 'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Setting password expiration to "One-time password" is not allowed for your own User~~', ]); diff --git a/datamodels/2.x/authent-local/dictionaries/tr.dict.authent-local.php b/datamodels/2.x/authent-local/dictionaries/tr.dict.authent-local.php index 58c46cf82..efd9ccd03 100644 --- a/datamodels/2.x/authent-local/dictionaries/tr.dict.authent-local.php +++ b/datamodels/2.x/authent-local/dictionaries/tr.dict.authent-local.php @@ -28,7 +28,7 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', [ 'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'Password cannot be changed by the user.~~', 'Class:UserLocal/Attribute:password_renewed_date' => 'Password renewed on~~', 'Class:UserLocal/Attribute:password_renewed_date+' => 'When the password was last changed~~', - 'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 8 characters and include uppercase, lowercase, numeric and special characters.~~', + 'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 12 characters and include uppercase, lowercase, numeric and special characters.~~', 'UserLocal:password:expiration' => 'The fields below require an extension~~', 'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Setting password expiration to "One-time password" is not allowed for your own User~~', ]); diff --git a/datamodels/2.x/authent-local/dictionaries/zh_cn.dict.authent-local.php b/datamodels/2.x/authent-local/dictionaries/zh_cn.dict.authent-local.php index c7da16e7f..84123ac70 100644 --- a/datamodels/2.x/authent-local/dictionaries/zh_cn.dict.authent-local.php +++ b/datamodels/2.x/authent-local/dictionaries/zh_cn.dict.authent-local.php @@ -51,7 +51,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', [ 'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => '用户不允许修改密码.', 'Class:UserLocal/Attribute:password_renewed_date' => '密码更新', 'Class:UserLocal/Attribute:password_renewed_date+' => '上次修改密码的时间', - 'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => '密码必须至少8个字符, 包含大小写, 数字和特殊字符.', + 'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => '密码必须至少12个字符, 包含大小写, 数字和特殊字符.', 'UserLocal:password:expiration' => '下面的区域需要插件扩展', 'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => '不允许用户为自己设置 "一次性密码" 的失效期限', ]); diff --git a/datamodels/2.x/combodo-db-tools/bin/rebuildhk.php b/datamodels/2.x/combodo-db-tools/bin/rebuildhk.php index 965e562d6..472eee074 100644 --- a/datamodels/2.x/combodo-db-tools/bin/rebuildhk.php +++ b/datamodels/2.x/combodo-db-tools/bin/rebuildhk.php @@ -10,22 +10,87 @@ */ use Combodo\iTop\Core\MetaModel\HierarchicalKey; +use Combodo\iTop\DBTools\Enum\BinExitCode; +use Combodo\iTop\DBTools\Exception\AuthenticationException; -require_once('../../../approot.inc.php'); +// env-xxx folders +if (file_exists(__DIR__.'/../../../approot.inc.php')) { + require_once __DIR__.'/../../../approot.inc.php'; +} +// datamodel/2.x and data/xxx-modules folders +elseif (file_exists(__DIR__.'/../../../../approot.inc.php')) { + require_once __DIR__.'/../../../../approot.inc.php'; +} require_once APPROOT.'application/startup.inc.php'; -foreach (MetaModel::GetClasses() as $sClass) { - if (!MetaModel::HasTable($sClass)) { - continue; - } +// Prepare output page +$sPageTitle = "Database maintenance tools - Report"; +$bIsModeCLI = utils::IsModeCLI(); +if ($bIsModeCLI) { + $oP = new CLIPage($sPageTitle); - foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) { - // Check (once) all the attributes that are hierarchical keys - if ((MetaModel::GetAttributeOrigin($sClass, $sAttCode) == $sClass) && $oAttDef->IsHierarchicalKey()) { - echo "Rebuild hierarchical key $sAttCode from $sClass.\n"; - HierarchicalKey::Rebuild($sClass, $sAttCode, $oAttDef); - } - } + SetupUtils::CheckPhpAndExtensionsForCli($oP, BinExitCode::FATAL->value); +} else { + $oP = new WebPage($sPageTitle); } -echo "Done\n"; +// Authentication logic +try { + utils::UseParamFile(); + + if ($bIsModeCLI) { + $sAuthUser = utils::ReadParam('auth_user', null, true, utils::ENUM_SANITIZATION_FILTER_RAW_DATA); + $sAuthPwd = utils::ReadParam('auth_pwd', null, true, utils::ENUM_SANITIZATION_FILTER_RAW_DATA); + if (utils::IsNullOrEmptyString($sAuthUser) || utils::IsNullOrEmptyString($sAuthPwd)) { + throw new AuthenticationException("Access credentials not provided, usage: php rebuildhk.php --auth_user= --auth_pwd= [--param_file=]"); + } + if (UserRights::CheckCredentials($sAuthUser, $sAuthPwd)) { + UserRights::Login($sAuthUser); + } else { + throw new AuthenticationException("Access wrong credentials ('$sAuthUser')"); + } + } else { + // Check user rights and prompt if needed + LoginWebPage::DoLoginEx(null, true); + } + + if (!UserRights::IsAdministrator()) { + throw new AuthenticationException("Access restricted to administrators"); + } +} catch (AuthenticationException $oException) { + $oP->p($oException->getMessage()); + $oP->output(); + exit(BinExitCode::ERROR->value); +} catch (Exception $oException) { + $oP->p("Error: ".$oException->GetMessage()); + $oP->output(); + exit(BinExitCode::FATAL->value); +} + +// Business logic +try { + foreach (MetaModel::GetClasses() as $sClass) { + if (!MetaModel::HasTable($sClass)) { + continue; + } + + foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef) { + // Check (once) all the attributes that are hierarchical keys + if ((MetaModel::GetAttributeOrigin($sClass, $sAttCode) == $sClass) && $oAttDef->IsHierarchicalKey()) { + $oP->p("Rebuild hierarchical key $sAttCode from $sClass."); + HierarchicalKey::Rebuild($sClass, $sAttCode, $oAttDef); + } + } + } + + $oP->p("Done"); + $oP->output(); +} catch (AuthenticationException $oException) { + $oP->p($oException->getMessage()); + $oP->output(); + exit(BinExitCode::ERROR->value); +} catch (Exception $oException) { + $oP->p("Error: ".$oException->GetMessage()); + $oP->output(); + exit(BinExitCode::FATAL->value); +} diff --git a/datamodels/2.x/combodo-db-tools/bin/report.php b/datamodels/2.x/combodo-db-tools/bin/report.php index ae69443fd..4cf780db5 100644 --- a/datamodels/2.x/combodo-db-tools/bin/report.php +++ b/datamodels/2.x/combodo-db-tools/bin/report.php @@ -5,22 +5,93 @@ * @license http://opensource.org/licenses/AGPL-3.0 */ +use Combodo\iTop\DBTools\Enum\BinExitCode; +use Combodo\iTop\DBTools\Exception\AuthenticationException; use Combodo\iTop\DBTools\Service\DBAnalyzerUtils; -require_once('../../../approot.inc.php'); -require_once(APPROOT.'application/startup.inc.php'); - -require_once('../db_analyzer.class.inc.php'); -require_once('../src/Service/DBAnalyzerUtils.php'); - -$oDBAnalyzer = new DatabaseAnalyzer(0); -$aResults = $oDBAnalyzer->CheckIntegrity([]); - -if (empty($aResults)) { - echo "Database OK\n"; - exit(0); +// env-xxx folders +if (file_exists(__DIR__.'/../../../approot.inc.php')) { + require_once __DIR__.'/../../../approot.inc.php'; +} +// datamodel/2.x and data/xxx-modules folders +elseif (file_exists(__DIR__.'/../../../../approot.inc.php')) { + require_once __DIR__.'/../../../../approot.inc.php'; } -$sReportFile = DBAnalyzerUtils::GenerateReport($aResults); +require_once APPROOT.'application/startup.inc.php'; +require_once APPROOT.'application/loginwebpage.class.inc.php'; -echo "Report generated: {$sReportFile}.log\n"; +require_once __DIR__.'/../db_analyzer.class.inc.php'; + +// Prepare output page +$sPageTitle = "Database maintenance tools - Report"; +$bIsModeCLI = utils::IsModeCLI(); +if ($bIsModeCLI) { + $oP = new CLIPage($sPageTitle); + + SetupUtils::CheckPhpAndExtensionsForCli($oP, BinExitCode::FATAL->value); +} else { + $oP = new WebPage($sPageTitle); +} + +// Authentication logic +try { + utils::UseParamFile(); + + if ($bIsModeCLI) { + $sAuthUser = utils::ReadParam('auth_user', null, true, utils::ENUM_SANITIZATION_FILTER_RAW_DATA); + $sAuthPwd = utils::ReadParam('auth_pwd', null, true, utils::ENUM_SANITIZATION_FILTER_RAW_DATA); + if (utils::IsNullOrEmptyString($sAuthUser) || utils::IsNullOrEmptyString($sAuthPwd)) { + throw new AuthenticationException("Access credentials not provided, usage: php report.php --auth_user= --auth_pwd= [--param_file=]"); + } + if (UserRights::CheckCredentials($sAuthUser, $sAuthPwd)) { + UserRights::Login($sAuthUser); + } else { + throw new AuthenticationException("Access wrong credentials ('$sAuthUser')"); + } + } else { + // Check user rights and prompt if needed + LoginWebPage::DoLoginEx(null, true); + } + + if (!UserRights::IsAdministrator()) { + throw new AuthenticationException("Access restricted to administrators"); + } +} catch (AuthenticationException $oException) { + $sExceptionMessage = $oP instanceof WebPage ? utils::EscapeHtml($oException->getMessage()) : $oException->getMessage(); + $oP->p($sExceptionMessage); + $oP->output(); + exit(BinExitCode::ERROR->value); +} catch (Exception $oException) { + $sExceptionMessage = $oP instanceof WebPage ? utils::EscapeHtml($oException->getMessage()) : $oException->getMessage(); + $oP->p("Error: ".$sExceptionMessage); + $oP->output(); + exit(BinExitCode::FATAL->value); +} + +// Business logic +try { + $oDBAnalyzer = new DatabaseAnalyzer(0); + $aResults = $oDBAnalyzer->CheckIntegrity([]); + + if (empty($aResults)) { + $oP->p("Database OK"); + $oP->output(); + exit(BinExitCode::SUCCESS->value); + } + + $sReportFile = DBAnalyzerUtils::GenerateReport($aResults); + + $oP->p("Report generated: {$sReportFile}.log"); + $oP->output(); +} catch (AuthenticationException $oException) { + $sExceptionMessage = $oP instanceof WebPage ? utils::EscapeHtml($oException->getMessage()) : $oException->getMessage(); + $oP->p($sExceptionMessage); + $oP->output(); + exit(BinExitCode::ERROR->value); +} catch (Exception $oException) { + $sExceptionMessage = $oP instanceof WebPage ? utils::EscapeHtml($oException->getMessage()) : $oException->getMessage(); + $oP->p("Error: ".$sExceptionMessage); + $oP->output(); + exit(BinExitCode::FATAL->value); +} diff --git a/datamodels/2.x/combodo-db-tools/composer.json b/datamodels/2.x/combodo-db-tools/composer.json new file mode 100644 index 000000000..e42db1c6d --- /dev/null +++ b/datamodels/2.x/combodo-db-tools/composer.json @@ -0,0 +1,9 @@ +{ + "name": "combodo/combodo-db-tools", + "license": "AGPL-3.0-only", + "autoload": { + "psr-4": { + "Combodo\\iTop\\DBTools\\": "src/" + } + } +} diff --git a/datamodels/2.x/combodo-db-tools/composer.lock b/datamodels/2.x/combodo-db-tools/composer.lock new file mode 100644 index 000000000..4c59cd0a4 --- /dev/null +++ b/datamodels/2.x/combodo-db-tools/composer.lock @@ -0,0 +1,18 @@ +{ + "_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": "38292b9b3a56c6c8776285a17c58034e", + "packages": [], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": {}, + "prefer-stable": false, + "prefer-lowest": false, + "platform": {}, + "platform-dev": {}, + "plugin-api-version": "2.6.0" +} diff --git a/datamodels/2.x/combodo-db-tools/module.combodo-db-tools.php b/datamodels/2.x/combodo-db-tools/module.combodo-db-tools.php index a2a33fd89..15516da32 100644 --- a/datamodels/2.x/combodo-db-tools/module.combodo-db-tools.php +++ b/datamodels/2.x/combodo-db-tools/module.combodo-db-tools.php @@ -30,7 +30,7 @@ SetupWebPage::AddModule( // Identification // 'label' => 'Database maintenance tools', - 'category' => 'business', + 'category' => 'Application management', // Setup // @@ -43,6 +43,7 @@ SetupWebPage::AddModule( // Components // 'datamodel' => [ + 'vendor/autoload.php', 'src/Service/DBToolsUtils.php', 'src/Service/DBAnalyzerUtils.php', ], diff --git a/datamodels/2.x/combodo-db-tools/src/Enum/BinExitCode.php b/datamodels/2.x/combodo-db-tools/src/Enum/BinExitCode.php new file mode 100644 index 000000000..ba27db42a --- /dev/null +++ b/datamodels/2.x/combodo-db-tools/src/Enum/BinExitCode.php @@ -0,0 +1,18 @@ + + * 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-db-tools/vendor/composer/InstalledVersions.php b/datamodels/2.x/combodo-db-tools/vendor/composer/InstalledVersions.php new file mode 100644 index 000000000..6d29bff66 --- /dev/null +++ b/datamodels/2.x/combodo-db-tools/vendor/composer/InstalledVersions.php @@ -0,0 +1,378 @@ + + * 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 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 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 = strtr(__DIR__, '\\', '/'); + 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-db-tools/vendor/composer/LICENSE b/datamodels/2.x/combodo-db-tools/vendor/composer/LICENSE new file mode 100644 index 000000000..f27399a04 --- /dev/null +++ b/datamodels/2.x/combodo-db-tools/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-db-tools/vendor/composer/autoload_classmap.php b/datamodels/2.x/combodo-db-tools/vendor/composer/autoload_classmap.php new file mode 100644 index 000000000..24ee7c066 --- /dev/null +++ b/datamodels/2.x/combodo-db-tools/vendor/composer/autoload_classmap.php @@ -0,0 +1,15 @@ + $baseDir . '/src/Enum/BinExitCode.php', + 'Combodo\\iTop\\DBTools\\Exception\\AuthenticationException' => $baseDir . '/src/Exception/AuthenticationException.php', + 'Combodo\\iTop\\DBTools\\Service\\BinUtils' => $baseDir . '/src/Service/BinUtils.php', + 'Combodo\\iTop\\DBTools\\Service\\DBAnalyzerUtils' => $baseDir . '/src/Service/DBAnalyzerUtils.php', + 'Combodo\\iTop\\DBTools\\Service\\DBToolsUtils' => $baseDir . '/src/Service/DBToolsUtils.php', + 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php', +); diff --git a/datamodels/2.x/combodo-db-tools/vendor/composer/autoload_namespaces.php b/datamodels/2.x/combodo-db-tools/vendor/composer/autoload_namespaces.php new file mode 100644 index 000000000..15a2ff3ad --- /dev/null +++ b/datamodels/2.x/combodo-db-tools/vendor/composer/autoload_namespaces.php @@ -0,0 +1,9 @@ + array($baseDir . '/src'), +); diff --git a/datamodels/2.x/combodo-db-tools/vendor/composer/autoload_real.php b/datamodels/2.x/combodo-db-tools/vendor/composer/autoload_real.php new file mode 100644 index 000000000..51053e4c9 --- /dev/null +++ b/datamodels/2.x/combodo-db-tools/vendor/composer/autoload_real.php @@ -0,0 +1,37 @@ +setClassMapAuthoritative(true); + $loader->register(true); + + return $loader; + } +} diff --git a/datamodels/2.x/combodo-db-tools/vendor/composer/autoload_static.php b/datamodels/2.x/combodo-db-tools/vendor/composer/autoload_static.php new file mode 100644 index 000000000..b3e3c65fb --- /dev/null +++ b/datamodels/2.x/combodo-db-tools/vendor/composer/autoload_static.php @@ -0,0 +1,41 @@ + + array ( + 'Combodo\\iTop\\DBTools\\' => 21, + ), + ); + + public static $prefixDirsPsr4 = array ( + 'Combodo\\iTop\\DBTools\\' => + array ( + 0 => __DIR__ . '/../..' . '/src', + ), + ); + + public static $classMap = array ( + 'Combodo\\iTop\\DBTools\\Enum\\BinExitCode' => __DIR__ . '/../..' . '/src/Enum/BinExitCode.php', + 'Combodo\\iTop\\DBTools\\Exception\\AuthenticationException' => __DIR__ . '/../..' . '/src/Exception/AuthenticationException.php', + 'Combodo\\iTop\\DBTools\\Service\\BinUtils' => __DIR__ . '/../..' . '/src/Service/BinUtils.php', + 'Combodo\\iTop\\DBTools\\Service\\DBAnalyzerUtils' => __DIR__ . '/../..' . '/src/Service/DBAnalyzerUtils.php', + 'Combodo\\iTop\\DBTools\\Service\\DBToolsUtils' => __DIR__ . '/../..' . '/src/Service/DBToolsUtils.php', + 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixLengthsPsr4 = ComposerStaticInit38292b9b3a56c6c8776285a17c58034e::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInit38292b9b3a56c6c8776285a17c58034e::$prefixDirsPsr4; + $loader->classMap = ComposerStaticInit38292b9b3a56c6c8776285a17c58034e::$classMap; + + }, null, ClassLoader::class); + } +} diff --git a/datamodels/2.x/combodo-db-tools/vendor/composer/installed.json b/datamodels/2.x/combodo-db-tools/vendor/composer/installed.json new file mode 100644 index 000000000..87fda747e --- /dev/null +++ b/datamodels/2.x/combodo-db-tools/vendor/composer/installed.json @@ -0,0 +1,5 @@ +{ + "packages": [], + "dev": true, + "dev-package-names": [] +} diff --git a/datamodels/2.x/combodo-db-tools/vendor/composer/installed.php b/datamodels/2.x/combodo-db-tools/vendor/composer/installed.php new file mode 100644 index 000000000..acd492788 --- /dev/null +++ b/datamodels/2.x/combodo-db-tools/vendor/composer/installed.php @@ -0,0 +1,23 @@ + array( + 'name' => 'combodo/combodo-db-tools', + 'pretty_version' => '1.0.0+no-version-set', + 'version' => '1.0.0.0', + 'reference' => null, + 'type' => 'library', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'dev' => true, + ), + 'versions' => array( + 'combodo/combodo-db-tools' => array( + 'pretty_version' => '1.0.0+no-version-set', + 'version' => '1.0.0.0', + 'reference' => null, + 'type' => 'library', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'dev_requirement' => false, + ), + ), +); diff --git a/datamodels/2.x/installation.xml b/datamodels/2.x/installation.xml index a3e53c2d0..65660323d 100755 --- a/datamodels/2.x/installation.xml +++ b/datamodels/2.x/installation.xml @@ -71,6 +71,19 @@ itop-virtualization-mgmt true + + + + itop-container-mgmt + Containerization + + + itop-container-mgmt + + false + + + diff --git a/datamodels/2.x/itop-backup/check-backup.php b/datamodels/2.x/itop-backup/check-backup.php index 04dfada1e..15c0fd4fa 100644 --- a/datamodels/2.x/itop-backup/check-backup.php +++ b/datamodels/2.x/itop-backup/check-backup.php @@ -199,15 +199,15 @@ function RaiseAlarm($sMessage) ////////// // Main -try { - utils::UseParamFile(); -} catch (Exception $e) { - echo "Error: ".$e->GetMessage()."\n"; - exit; -} - if (utils::IsModeCLI()) { - SetupUtils::CheckPhpAndExtensionsForCli(new CLIPage('Check backup utility')); + try { + utils::UseParamFile(); + } catch (Exception $e) { + echo 'Error: '.$e->GetMessage()."\n"; + exit; + } + $oP = new CLIPage('Check backup utility'); + SetupUtils::CheckPhpAndExtensionsForCli($oP); echo date('Y-m-d H:i:s')." - running check-backup utility\n"; try { diff --git a/datamodels/2.x/itop-backup/common.cli-execution.php b/datamodels/2.x/itop-backup/common.cli-execution.php index 756896066..0ac63a063 100644 --- a/datamodels/2.x/itop-backup/common.cli-execution.php +++ b/datamodels/2.x/itop-backup/common.cli-execution.php @@ -88,16 +88,15 @@ if (utils::IsModeCLI()) { $oP = new CLIPage(GetOperationName()); SetupUtils::CheckPhpAndExtensionsForCli($oP); + try { + utils::UseParamFile(); + } catch (Exception $e) { + ExitError($oP, $e->GetMessage()); + } } else { $oP = new WebPage(GetOperationName()); } -try { - utils::UseParamFile(); -} catch (Exception $e) { - ExitError($oP, $e->GetMessage()); -} - ExecuteMainOperation($oP); $oP->output(); diff --git a/datamodels/2.x/itop-backup/dbrestore.class.inc.php b/datamodels/2.x/itop-backup/dbrestore.class.inc.php index 5873145a9..e8ffe53d1 100644 --- a/datamodels/2.x/itop-backup/dbrestore.class.inc.php +++ b/datamodels/2.x/itop-backup/dbrestore.class.inc.php @@ -24,7 +24,7 @@ class DBRestore extends DBBackup /** @var string */ private $sDBUser; - public function __construct(\Config $oConfig = null) + public function __construct(?\Config $oConfig = null) { parent::__construct($oConfig); diff --git a/datamodels/2.x/itop-backup/module.itop-backup.php b/datamodels/2.x/itop-backup/module.itop-backup.php index 35fd85f0b..24c69bdc7 100644 --- a/datamodels/2.x/itop-backup/module.itop-backup.php +++ b/datamodels/2.x/itop-backup/module.itop-backup.php @@ -41,6 +41,11 @@ SetupWebPage::AddModule( 'doc.manual_setup' => '', 'doc.more_information' => '', + // Security + 'delegated_authentication_endpoints' => [ + 'ajax.backup.php', + ], + // Default settings // 'settings' => [ diff --git a/datamodels/2.x/itop-config-mgmt/data/en_us.data.itop-brand.xml b/datamodels/2.x/itop-config-mgmt/data/en_us.data.itop-brand.xml index 0c911123d..0518c0690 100755 --- a/datamodels/2.x/itop-config-mgmt/data/en_us.data.itop-brand.xml +++ b/datamodels/2.x/itop-config-mgmt/data/en_us.data.itop-brand.xml @@ -1,42 +1,205 @@ - - Acer - - - Apple - - - Asus - - - Cisco - - - Dell - - - HP Inc - - - HPE - - - IBM - - - Lenovo - - - Razer - - - Samsung - - - Sony - - - Toshiba - + + Acer + image/svg+xmlicon-acer.svgPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+Cjxzdmc6c3ZnIHhtbG5zOmlua3NjYXBlPSJodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy9uYW1lc3BhY2VzL2lua3NjYXBlIiB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiIHhtbG5zOnN2Zz0iaH + R0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgaWQ9ImFjZXIiIHg9IjBweCIgeT0iMHB4IiB3aWR0aD0iODMiIGhlaWdodD0iODMiIHZpZXdCb3g9IjAgMCA4MyA4MyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgc29kaXBvZGk6ZG9jbmFtZT0iaWNvbi1hY2VyLnN2ZyIgaW5rc2NhcGU6dmVyc2lvbj0iMS40LjMgKDBkMTVmNzUwNDIsIDIwMjUtMTItMjUpIj48c3ZnOmRlZnMgaWQ9ImRlZnMxIi8+PHNvZGlwb2RpOm5hbWVkdmlldyBpZD0ibmFtZWR2 + aWV3MSIgcGFnZWNvbG9yPSIjZmZmZmZmIiBib3JkZXJjb2xvcj0iIzAwMDAwMCIgYm9yZGVyb3BhY2l0eT0iMC4yNSIgaW5rc2NhcGU6c2hvd3BhZ2VzaGFkb3c9IjIiIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiIGlua3NjYXBlOnBhZ2VjaGVja2VyYm9hcmQ9IjAiIGlua3NjYXBlOmRlc2tjb2xvcj0iI2QxZDFkMSIgc2hvd2d1aWRlcz0idHJ1ZSIgaW5rc2NhcGU6em9vbT0iMTAuNDgzMDcxIiBpbmtzY2FwZTpjeD0iNzUuNzg4ODYiIGlua3NjYXBlOmN5PSIzNS + 42NzY1NjgiIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMjU2MCIgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iMTM2MCIgaW5rc2NhcGU6d2luZG93LXg9IjAiIGlua3NjYXBlOndpbmRvdy15PSIwIiBpbmtzY2FwZTp3aW5kb3ctbWF4aW1pemVkPSIxIiBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJhY2VyIj48c29kaXBvZGk6Z3VpZGUgcG9zaXRpb249IjQwLjMwNzkxOSw0MS4yMjAyMTQiIG9yaWVudGF0aW9uPSIwLC0xIiBpZD0iZ3VpZGUxIiBpbmtzY2FwZTpsb2NrZWQ9 + ImZhbHNlIi8+PC9zb2RpcG9kaTpuYW1lZHZpZXc+Cjxzdmc6cGF0aCBpZD0iYWNlci1sb2dvIiBzdHlsZT0iZmlsbDojODBjMzQzIiBkPSJtIDgyLjg1LDMyLjc2MDg5MyBjIC0wLjI5LC0wLjQyIC0wLjYyLC0wLjcgLTIuMDQsLTAuODEgLTAuMzcsLTAuMDMgLTEuNiwtMC4wNyAtMy42NiwtMC4wNyAtNS40MiwwIC05LjEsMS42NSAtMTAuOTgsNC45MSAwLjUyLC0zLjI4IC0yLjY3LC00LjkyIC05LjU1LC00LjkyIC04LjA5LDAgLTEzLjE0LDMuMjcgLTE1LjE1LDkuOD + EgLTAuNzQsMS45MSAtMC44Miw0LjAyIC0wLjIzLDUuOTggbCAtMS45MSwwLjEzIGMgLTEuNDksMC4xMSAtMy40NiwwLjIyIC00LjY2LDAuMjIgLTIuOTYsMCAtNC44LC0wLjUgLTUuNTEsLTEuNSAtMC42NCwtMC45IC0wLjU3LC0yLjU2IDAuMTcsLTQuOTggMS4yMywtNC4wMiA0LjI5LC01LjgyIDkuMTgsLTUuODIgMi41MywwIDUsMC4yNyA1LDAuMjcgMC4zLC0wLjA1IDAuNTEsLTAuMzMgMC40NiwtMC42NCAwLC0wLjAxIDAsLTAuMDIgLTAuMDEsLTAuMDMgbCAtMC4w + NSwtMC4zOCAtMC4xNywtMS4zNSBjIC0wLjExLC0wLjg5IC0wLjc3LC0xLjQxIC0xLjk3LC0xLjU3IC0xLjEsLTAuMDcgLTEuOTEsLTAuMTMgLTMuMTIsLTAuMTMgaCAtMC4wNyBjIC02LjM5LDAuMDEgLTEwLjg0LDIuMTIgLTEzLjM2LDYuMzIgMC45MiwtNC4yMSAtMi4wNCwtNi4zMiAtOC44NywtNi4zMiAtMi43MywtMC4wNSAtNS40NiwwLjA2IC04LjE4LDAuMzMgLTEuMDMsLTAuMDMgLTEuOTYsMC42MSAtMi4zMywxLjU3IGwgLTAuNTQsMS43MyBjIC0wLjEsMC4zMi + AwLjA1LDAuNDggMC40NiwwLjQ4IGggMC4wMSBjIDAuMywtMC4wNCAxLjQ2LC0wLjE1IDMuNDQsLTAuMzEgMi42MiwtMC4yMSA0LjU1LC0wLjMyIDUuODMsLTAuMzIgMy43NywwIDUuMzUsMC45NSA0Ljc2LDIuODQgLTAuMTEsMC40IC0wLjQ0LDAuNzEgLTAuODUsMC43OCAtMy41NiwwLjU5IC02LjM5LDEuMDIgLTguNDgsMS4yOCAtNS44OSwwLjc1IC05LjI5LDIuNTkgLTEwLjIsNS41MiAtMS4yNSw0LjAzIDEuODksNi4wNCA5LjQ0LDYuMDQgMy4xNywwLjA0IDYuMzQs + LTAuMTggOS40OCwtMC42NSAxLjQ3LC0wLjI1IDIuMjIsLTAuNjMgMi41MSwtMS41OCBsIDEuNDEsLTQuNDkgYyAtMC4xNSw0LjQ5IDIuOTksNi43NSA5LjQxLDYuNzUgMi4yMywwLjA0IDQuNDUsLTAuMDYgNi42NiwtMC4zMSAxLjMyLC0wLjIzIDEuOTUsLTAuNTIgMi4yNCwtMS41MSBsIDAuMjgsLTEuNDEgYyAxLjM3LDIuMTQgNC4zNywzLjIxIDkuMDEsMy4yMSA0Ljg5LDAgNy43NCwtMC4xNCA4LjU1LC0wLjQxIDAuNTcsLTAuMTIgMS4wNCwtMC41MiAxLjI1LC0xLj + A2IDAuMDMsLTAuMDkgMC4wNSwtMC4xOSAwLjA2LC0wLjI4IGwgMC41OSwtMS45MSBjIDAuMSwtMC4zMyAtMC4wNSwtMC40OSAtMC40NSwtMC40OCBsIC0zLjEzLDAuMTUgYyAtMi4wOSwwLjEyIC0zLjcyLDAuMTggLTQuOSwwLjE3IC0xLjU0LDAuMDggLTMuMDgsLTAuMDcgLTQuNTgsLTAuNDYgLTEuMiwtMC40MSAtMS45NCwtMS42MSAtMS43NywtMi44NiBsIDkuOTEsLTEuMjcgYyA0LjQ0LC0wLjU3IDcuNDIsLTEuOTQgOC45MiwtNC4xMiBsIC0zLjM3LDExLjczIGMg + LTAuMDcsMC4xOCAtMC4wNCwwLjM4IDAuMDcsMC41MyAwLjE4LDAuMTcgMC40MSwwLjI1IDAuNjUsMC4yMiBoIDQuMSBjIDAuNDcsMC4wNyAwLjkzLC0wLjIyIDEuMDYsLTAuNjggbCAzLjYyLC0xMi42NyBjIDAuNDgsLTEuNjcgMiwtMi40OCA0LjY3LC0yLjQ4IDIuNDEsMCA0LjIyLDAuMDIgNS4zOCwwLjA3IDAuMDMsMCAwLjA2LDAgMC4wOSwwIDAuMzksMCAwLjc0LC0wLjI2IDAuODQsLTAuNjMgbCAwLjYzLC0xLjc0IGMgMC4xNSwtMC4zIDAuMTIsLTAuNjMgLTAuMD + UsLTAuODkgbSAtNjYuMTIsMTUuMjQgYyAtMS44MywwLjIzIC0zLjY4LDAuMzMgLTUuNTIsMC4zIC00LjE3LDAgLTUuOTksLTAuODQgLTUuNDYsLTIuNTMgMC4zOCwtMS4yMSAxLjQ3LC0xLjk0IDMuMjgsLTIuMTkgbCA5LjQ4LC0xLjI4IHogbSA0My44MywtMTAuMjcgYyAtMC40LDEuMyAtMi4yNSwyLjE5IC01LjU2LDIuNjcgbCAtNy45LDEuMTMgMC4yLC0wLjY1IGMgMC4zOSwtMS43NCAxLjM3LC0zLjI4IDIuNzksLTQuMzcgMS4yLC0wLjc3IDMuMTUsLTEuMTYgNS44NiwtMS4xNiAzLjU2LDAgNS4xLDAuOCA0LjYxLDIuMzgiLz4KPC9zdmc6c3ZnPgo=0 + Brand + Acer + + + Apple + image/svg+xmlicons8-mac-os.svgPD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNDggNDgiIHdpZHRoPSI0OHB4IiBoZWlnaHQ9IjQ4cHgiPjxwYXRoIGZpbGw9IiMwODgzZDkiIGQ9Ik0zNi4yMzIsMjMuOTg1YzAtNS44NjUsNC43NjYtOC41MSw0Ljk2Ni04LjYzNmMtMi41OTYtMy45OTMtNi43OS00LjQ2Ny + 04LjM2Mi00LjQ2OCBjLTMuNjQzLDAtNi44NjMsMi4wMjItOC41ODUsMi4wMjJjLTEuNzk3LDAtNC40MTgtMi4xMjEtNy4zNjMtMi4wMjJjLTMuODQzLDAuMDc1LTcuMzYzLDIuMzQ2LTkuMzM0LDUuNjkxIGMtMS4zOTcsMi4zOTYtMS45NDcsNS4yMTctMS44OTYsOC4wODdjMC4wMDIsMC4xMTMsMC4wMTcsMC4yMjgsMC4wMiwwLjM0MUgzNi4zMkMzNi4yNzksMjQuNjcxLDM2LjI0MywyNC4zMzcsMzYuMjMyLDIzLjk4NXoiLz48cGF0aCBmaWxsPSIjMDg4M2Q5IiBkPSJN + MzAuNTY1LDcuMDYzQzMyLjI2MSw1LjE5MSwzMy4yMSwyLjYyMSwzMy4wNiwwYy0yLjM0NiwwLTUuMDY2LDEuMzcyLTYuNzg4LDMuMzk0IGMtMS4zNDgsMS42NzItMi43OTUsNC4yOTMtMi4yNzEsNi45MTNDMjYuNDIyLDEwLjYwNywyOS4wNDMsOS4wODUsMzAuNTY1LDcuMDYzeiIvPjxwYXRoIGZpbGw9IiMwMzcwYzgiIGQ9Ik0xNy41MTEsNDVjMi43NzEsMCwzLjc5NC0xLjg0OCw3LjQxMy0xLjg0OGMzLjM3LDAsNC40MTgsMS44NDgsNy4zMzgsMS44NDggYzMuMDcsMCw1LjA5Mi0yLjc5NSw2LjkxMy01LjU2N2MyLjI5NS0zLjIxOCwzLjA3LTYuMjg4LDMuMTY5LTYuNDE0Yy0wLjA5NCwwLTUuMjg3LTIuMTEyLTYuMDI2LTguMDE5SDUuNjc4IGMwLjE1Nyw1LjMxMSwyLjIyOCwxMC43OSw0LjY3MSwxNC4zMDlDMTIuMjcsNDIuMDU1LDE0LjQ0MSw0NSwxNy41MTEsNDV6Ii8+PC9zdmc+Cg==0 + Brand + Apple + + + Asus + image/svg+xmlicons8-asus.svgPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiIHhtbG5zOnNvZGlwb2RpPSJodHRwOi8vc29kaXBvZGkuc291cmNlZm9yZ2UubmV0L0RURC9zb2RpcG9kaS0wLmR0ZCIgeG1sbnM9Imh0dHA6Ly93 + d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwLDAsMjU2LDI1NiIgd2lkdGg9IjY0cHgiIGhlaWdodD0iNjRweCIgZmlsbC1ydWxlPSJub256ZXJvIiB2ZXJzaW9uPSIxLjEiIGlkPSJzdmcxMyIgc29kaXBvZGk6ZG9jbmFtZT0iaWNvbnM4LWFzdXMgKDEpLnN2ZyIgaW5rc2NhcGU6dmVyc2lvbj0iMS40LjMgKDBkMTVmNzUwNDIsIDIwMjUtMTItMjUpIj48c29kaXBvZGk6bmFtZWR2aWV3IGlkPS + JuYW1lZHZpZXcxMyIgcGFnZWNvbG9yPSIjZmZmZmZmIiBib3JkZXJjb2xvcj0iIzAwMDAwMCIgYm9yZGVyb3BhY2l0eT0iMC4yNSIgaW5rc2NhcGU6c2hvd3BhZ2VzaGFkb3c9IjIiIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiIGlua3NjYXBlOnBhZ2VjaGVja2VyYm9hcmQ9IjAiIGlua3NjYXBlOmRlc2tjb2xvcj0iI2QxZDFkMSIgaW5rc2NhcGU6em9vbT0iMTcuMTg3NSIgaW5rc2NhcGU6Y3g9IjMxLjk3MDkwOSIgaW5rc2NhcGU6Y3k9IjMyIiBpbmtzY2FwZTp3 + aW5kb3ctd2lkdGg9IjI1NjAiIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjEzNjAiIGlua3NjYXBlOndpbmRvdy14PSIwIiBpbmtzY2FwZTp3aW5kb3cteT0iMCIgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSIgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0iZzEzIi8+PGRlZnMgaWQ9ImRlZnMxMCI+PHJhZGlhbEdyYWRpZW50IGN4PSIzNC42MjUiIGN5PSIzMS44NzUiIHI9IjIzLjIwNiIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIGlkPSJjb2xvci0xIj + 48c3RvcCBvZmZzZXQ9IjAiIHN0b3AtY29sb3I9IiNmNGU5YzMiIGlkPSJzdG9wMSIvPjxzdG9wIG9mZnNldD0iMC4yMTkiIHN0b3AtY29sb3I9IiNmOGVlY2QiIGlkPSJzdG9wMiIvPjxzdG9wIG9mZnNldD0iMC42NDQiIHN0b3AtY29sb3I9IiNmZGY0ZGMiIGlkPSJzdG9wMyIvPjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iI2ZmZjZlMSIgaWQ9InN0b3A0Ii8+PC9yYWRpYWxHcmFkaWVudD48bGluZWFyR3JhZGllbnQgeDE9IjAuMzY1IiB5MT0iMzIuNSIgeDI9 + IjY0IiB5Mj0iMzIuNSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIGlkPSJjb2xvci0yIj48c3RvcCBvZmZzZXQ9IjAuMDUzIiBzdG9wLWNvbG9yPSIjMDAwMDAwIiBpZD0ic3RvcDUiLz48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiMwMDAwMDAiIGlkPSJzdG9wNiIvPjwvbGluZWFyR3JhZGllbnQ+PHJhZGlhbEdyYWRpZW50IGN4PSIzNC42MjUiIGN5PSIzMS44NzUiIHI9IjIzLjIwNiIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIGlkPS + Jjb2xvci0zIj48c3RvcCBvZmZzZXQ9IjAiIHN0b3AtY29sb3I9IiNmNGU5YzMiIGlkPSJzdG9wNyIvPjxzdG9wIG9mZnNldD0iMC4yMTkiIHN0b3AtY29sb3I9IiNmOGVlY2QiIGlkPSJzdG9wOCIvPjxzdG9wIG9mZnNldD0iMC42NDQiIHN0b3AtY29sb3I9IiNmZGY0ZGMiIGlkPSJzdG9wOSIvPjxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iI2ZmZjZlMSIgaWQ9InN0b3AxMCIvPjwvcmFkaWFsR3JhZGllbnQ+PC9kZWZzPjxnIGZpbGw9Im5vbmUiIGZpbGwtcnVs + ZT0ibm9uemVybyIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIHN0cm9rZS1saW5lY2FwPSJidXR0IiBzdHJva2UtbGluZWpvaW49Im1pdGVyIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS1kYXNoYXJyYXk9IiIgc3Ryb2tlLWRhc2hvZmZzZXQ9IjAiIGZvbnQtZmFtaWx5PSJub25lIiBmb250LXdlaWdodD0ibm9uZSIgZm9udC1zaXplPSJub25lIiB0ZXh0LWFuY2hvcj0ibm9uZSIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOiBub3JtYWwiIGlkPSJnMT + MiPjxnIHRyYW5zZm9ybT0ic2NhbGUoNCw0KSIgaWQ9ImcxMiI+PHBhdGggZD0iTTYuMTU2LDI5LjI0M2wtNS43MjMsOS45MTljLTAuMTkyLDAuMzMzIDAuMDQ4LDAuNzUgMC40MzMsMC43NWgyLjc2NGMwLjM1NiwwIDAuNjg2LC0wLjE5IDAuODY1LC0wLjQ5OGw1LjYyOSwtOS43MDF6TTYuMjk5LDI5LjAwNWMwLDAgMC44MTUsLTEuNDg2IDEuNjI1LC0yLjkyYzAuMzU0LC0wLjYyOCAxLjAxOSwtMS4wMTQgMS43NCwtMS4wMTRjMS40MDgsMC4wMDEgMy43NTcsMC4wMDMg + NS4wODYsMC4wMDRjMC41NTIsMCAwLjk5NSwwLjQ0OCAwLjk5NSwxLjAwMXYyLjYxYzAsMCAwLjMyMywtMS4zODYgMC44OTEsLTIuMDQzYzAuNTM0LC0wLjYxOSAxLjI0NiwtMS40NzggMi44NzIsLTEuNTkyaDEwLjk2M2MwLjU1MiwwIDEsMC40NDggMSwxdjEuOTU1YzAsMC41NTIgLTAuNDQ4LDEgLTEsMXpNNjQsMjguMDA4di0xLjk1OGMwLC0wLjU1MiAtMC40NDgsLTEgLTEsLTFoLTExLjhjLTEuNjIyLDAuMTE0IC0yLjMzNywwLjk3MiAtMi44NzIsMS41OTJjLTAuNT + Y5LDAuNjU3IC0wLjg5LDIuMDQzIC0wLjg5LDIuMDQzdjAuMzE4bDE1LjU2MiwwLjAwNWMwLjU1MiwwIDEsLTAuNDQ4IDEsLTF6TTMzLjA5NSwyNS4wN2gxLjU3OGMwLjU1MiwwIDEsMC40NDggMSwxdjIuOTM1aC0zLjU3OHYtMi45MzVjMCwtMC41NTIgMC40NDgsLTEgMSwtMXpNNDQuODM5LDI1LjA3aDEuNTc0YzAuNTUyLDAgMSwwLjQ0OCAxLDF2Mi45MzVoLTMuNTc0di0yLjkzNWMwLC0wLjU1MiAwLjQ0NywtMSAxLC0xek00Ny40MTMsMzAuNDI1bC0zLjUxNCwtMC4y + MzN2NC41NjZjMCwwIC0wLjAxLDEuMzE0IC0xLjE1OCwxLjMxNGMtMS4xMzgsMCAtNi4wMzksMCAtNi4wMzksMGMwLDAgLTEuMDIzLC0wLjA5MyAtMS4wMjMsLTEuMzAzYzAsLTEuMjA3IDAsLTUuMTk2IDAsLTUuMTk2bC0zLjU0OSwtMC4yODV2Ny4wMDFjMC41NzQsMy4zNTkgMy4zMTEsMy42MTcgMy4zMTEsMy42MTdjMCwwIDAuMjc4LDAuMDIyIDAuMzI0LDAuMDI2aDguMTU2YzAsMCAzLjQ5MSwtMC4zMTEgMy40OTEsLTQuMDIzYzAuMDAxLC0zLjcxMyAwLjAwMSwtNS + 40ODQgMC4wMDEsLTUuNDg0ek0xMy4xMTEsMzkuOTE0aDE1LjczYzIuOTE0LC0wLjY0NyAzLjIxOCwtMy41NzcgMy4yMTgsLTMuNTc3YzAuMTM2LC0wLjg3MSAwLjA1NywtMS41NzQgMC4wNTcsLTEuNTc0Yy0wLjA4OCwtMC41ODggLTEuMDk0LC0zLjE3OCAtMy4yODEsLTMuNDA1Yy0xLjMwNCwtMC4xMzQgLTEyLjkxLC0xLjE1NSAtMTIuOTEsLTEuMTU1YzAuMjI1LDEuMjg4IDAuNzQ4LDEuOTM4IDEuMDk0LDIuMzExYzAuODA1LDAuODU3IDIuMDg3LDEuMDk5IDIuMDg3 + LDEuMDk5YzAuMzA5LDAuMDMzIDguOTQ1LDAuODI0IDguOTQ1LDAuODI0YzAuMjc0LDAuMDE3IDAuNzk3LDAuMDkzIDAuNzksMC44NDljMCwwLjA5MSAtMC4wNzUsMC43NTcgLTAuNzM4LDAuNzU3aC0xMi4wMTRjLTAuMjc2LDAgLTAuNSwtMC4yMjQgLTAuNSwtMC41di01LjM3M2wtMy40NzgsLTAuMjgxdjkuMDI3YzAsMC41NSAwLjQ0OCwwLjk5OCAxLDAuOTk4ek00Ny40NDQsMzcuMDE3YzAuMDAxLC0wLjU1MiAwLjQ0OCwtMC45OTggMSwtMC45OThoMTEuNDI5YzAuMj + g2LDAgMC41OTUsLTAuMTg3IDAuNTk1LC0wLjE4N2MwLjEzLC0wLjEyOSAwLjIzNSwtMC4zNjQgMC4yMzUsLTAuNTkxYzAsLTAuNzUzIC0wLjU2MSwtMC43ODYgLTAuODQzLC0wLjgwM2MwLDAgLTguNzMyLC0wLjgwOCAtOS4wMzYsLTAuODM0YzAsMCAtMS4yMTEsLTAuMjA3IC0yLjAxNywtMS4wNjhjLTAuMzUxLC0wLjM2OSAtMC44MTUsLTAuNzcxIC0xLjE2MSwtMi4wOTljMCwwIDExLjY3MSwwLjc2MyAxMi45NjgsMC44OTdjMi4xODksMC4yMzIgMy4yMTUsMi42MzIgMy4zMDgsMy40M2MwLDAgMC4wOTMsMC43MjIgLTAuMDIsMS42MDdjMCwwIC0wLjQ1NCwzLjM3NCAtMy42NjQsMy41NzloLTExLjc5N2MtMC41NTMsMCAtMS4wMDEsLTAuNDQ5IC0xLC0xLjAwMnoiIGZpbGw9InVybCgjY29sb3ItMikiIGlkPSJwYXRoMTEiLz48L2c+PC9nPjwvc3ZnPgo=0 + Brand + Asus + + + Cisco + image/svg+xmlicon-cisco.svgPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiIHhtbG5zOnNvZGlwb2RpPSJodHRwOi8vc29kaXBvZGkuc291cmNlZm9yZ2UubmV0L0RURC9zb2RpcG9kaS0wLmR0ZCIgeG1sbnM9Imh0dHA6Ly93d + 3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgd2lkdGg9IjEwOCIgaGVpZ2h0PSIxMDgiIHZpZXdCb3g9IjAgMCAxMDggMTA4IiByb2xlPSJpbWciIHZlcnNpb24 + 9IjEuMSIgaWQ9InN2ZzExIiBzb2RpcG9kaTpkb2NuYW1lPSJpY29uLWNpc2NvLnN2ZyIgaW5rc2NhcGU6dmVyc2lvbj0iMS40LjMgKDBkMTVmNzUwNDIsIDIwMjUtMTItMjUpIj48c29kaXBvZGk6bmFtZWR2aWV3IGlkPSJuYW1lZHZpZXcxMSIgcGFnZWNvbG9yPSIjZmZmZmZmIiBib3JkZXJjb2xvcj0iIzAwMDAwMCIgYm9yZGVyb3BhY2l0eT0iMC4yNSIgaW5rc2NhcGU6c2hvd3BhZ2VzaGFkb3c9IjIiIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiIGlua3NjYXBlO + nBhZ2VjaGVja2VyYm9hcmQ9IjAiIGlua3NjYXBlOmRlc2tjb2xvcj0iI2QxZDFkMSIgc2hvd2d1aWRlcz0idHJ1ZSIgaW5rc2NhcGU6em9vbT0iNi44MjI5NjAyIiBpbmtzY2FwZTpjeD0iNDguODc5MDc4IiBpbmtzY2FwZTpjeT0iNTEuNzM3MDc1IiBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjI1NjAiIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjEzNjAiIGlua3NjYXBlOndpbmRvdy14PSIwIiBpbmtzY2FwZTp3aW5kb3cteT0iMCIgaW5rc2NhcGU6d2luZG93LW1heGl + taXplZD0iMSIgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ic3ZnMTEiPjxzb2RpcG9kaTpndWlkZSBwb3NpdGlvbj0iMTYuOTM5NTg3LDUzLjM3NjMwMyIgb3JpZW50YXRpb249IjAsLTEiIGlkPSJndWlkZTExIiBpbmtzY2FwZTpsb2NrZWQ9ImZhbHNlIi8+PC9zb2RpcG9kaTpuYW1lZHZpZXc+PHRpdGxlIGlkPSJmdy1jLWhlYWRlcl9fbG9nby10aXRsZSI+Q2lzY28uY29tIEZyYW5jZTwvdGl0bGU+PGRlZnMgaWQ9ImRlZnMxIj48cGF0aCBkPSJtIDAsMjIuNzY5IGEgM + i4zNDgsMi4zNDggMCAwIDAgMy45MzUsMS41NDUgYyAwLjQzNCwtMC40MDMgMC43LC0wLjk1NSAwLjc0NCwtMS41NDUgdiAtNS4yIGEgMi4zNCwyLjM0IDAgMCAwIC00LjY3OSwwIHYgNS4yIiBpZD0iYmFyX3Nob3J0IiBjbGFzcz0iYmFyIi8+PHBhdGggZD0ibSAxMi45NSwyMi43NjkgYSAyLjM0OSwyLjM0OSAwIDAgMCAyLjM0LDIuMTcxIDIuMzQ2LDIuMzQ2IDAgMCAwIDIuMzM5LC0yLjE3MSBWIDExLjExMiBhIDIuMzQxLDIuMzQxIDAgMCAwIC00LjY3OSwwIFYgMjI + uNzciIGlkPSJiYXJfdGFsbCIgY2xhc3M9ImJhciIvPjxwYXRoIGQ9Im0gMjUuODMyLDI3LjQ2NCBhIDIuMzQ1LDIuMzQ1IDAgMCAwIDQuNjc4LDAgViAyLjI0OSBhIDIuMzQyLDIuMzQyIDAgMCAwIC00LjY3OCwwIHYgMjUuMjE1IiBpZD0iYmFyX2dyYW5kZSIgY2xhc3M9ImJhciIvPjxwYXRoIGQ9Im0gMjQuMDI2LDU2LjI3NyB2IC01LjAwMiBsIC0wLjA5OCwwLjA0MyBhIDkuMjUzLDkuMjUzIDAgMCAxIC0zLjYwNSwwLjkxNSA1LjMwMyw1LjMwMyAwIDAgMSAtMy42M + ywtMS4wNyA0LjY0NCw0LjY0NCAwIDAgMSAtMS41OCwtMi4yNDQgNS4zOTUsNS4zOTUgMCAwIDEgLTAuMTA2LC0zIDQuNiw0LjYgMCAwIDEgMS42MDksLTIuNTY2IDQuODIzLDQuODIzIDAgMCAxIDIuNTI4LC0xLjA5IDguMzMyLDguMzMyIDAgMCAxIDQuNzc0LDAuODk1IGwgMC4xMDgsMC4wNTYgdiAtNS4wMyBsIC0wLjIyOCwtMC4wNjEgYSAxMi43OCwxMi43OCAwIDAgMCAtNC41NTIsLTAuNTk2IDEwLjUzNCwxMC41MzQgMCAwIDAgLTQuMDY1LDAuOTMgOS4yOSw5LjI + 5IDAgMCAwIC0zLjMyOSwyLjU3MiAxMC4wMTQsMTAuMDE0IDAgMCAwIC0wLjE4MiwxMi4xOCA5LjU0Niw5LjU0NiAwIDAgMCA1LjI5MiwzLjQwMyBjIDIuMjExLDAuNTM4IDQuNTI4LDAuNDU2IDYuNjk3LC0wLjIzNCBsIDAuMzY3LC0wLjEwMSIgaWQ9ImNpc2NvX2MiLz48L2RlZnM+PGcgZmlsbD0iIzAyYzhmZiIgZmlsbC1ydWxlPSJldmVub2RkIiBpZD0iZzExIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMC4wOTQ2Njg1OSwyNi4yMzQ5NDYpIj48dXNlIGhyZWY9IiNja + XNjb19jIiBpZD0idXNlMSIvPjx1c2UgaHJlZj0iI2Npc2NvX2MiIHg9IjQ5LjUiIGlkPSJ1c2UyIi8+PHBhdGggZD0ibSA0MS42OSw1Mi4xMjUgLTAuMDE5LDQuMzA4IDAuMzE1LDAuMDU0IGMgMC45ODksMC4xODUgMS45ODcsMC4zMTMgMi45OSwwLjM4NSBhIDE4LjEsMTguMSAwIDAgMCAyLjY0MiwwLjA1MSBjIDAuODQyLC0wLjA2IDEuNjc1LC0wLjIxOCAyLjQ4LC0wLjQ2OCBhIDYuODYyLDYuODYyIDAgMCAwIDIuNTczLC0xLjM3MSA1LjE5LDUuMTkgMCAwIDAgMS4 + 0OTgsLTIuMTQ4IDUuOTEyLDUuOTEyIDAgMCAwIC0wLjAzLC00LjMyNCA0Ljg1Miw0Ljg1MiAwIDAgMCAtMS4zNDMsLTEuODYyIDUuNTY4LDUuNTY4IDAgMCAwIC0xLjk3LC0xLjE0NyBsIC0zLjI1LC0xLjIwNiBhIDEuNzQyLDEuNzQyIDAgMCAxIC0wLjg4NywtMC44NDUgMS4xMDcsMS4xMDcgMCAwIDEgMC4wMzYsLTAuOTg2IDEuMjksMS4yOSAwIDAgMSAwLjIxNywtMC4yOTEgMS43NSwxLjc1IDAgMCAxIDAuNDgsLTAuMzQ3IGMgMC4zNjMsLTAuMTggMC43NTUsLTAuM + jkzIDEuMTU4LC0wLjMzNyBhIDYuNzYsNi43NiAwIDAgMSAyLjA3MiwwLjAyMiBjIDAuODEsMC4wODggMS42MTMsMC4yMzEgMi40MDIsMC40MyBsIDAuMTY4LDAuMDM3IHYgLTMuOTc0IGwgLTAuMzEsLTAuMDY3IGEgMjEuMTQsMjEuMTQgMCAwIDAgLTIuNDQ0LC0wLjQzNSAxMi41NDUsMTIuNTQ1IDAgMCAwIC0zLjIxMywtMC4wMTQgNi45NDUsNi45NDUgMCAwIDAgLTMuNjk5LDEuNDg4IDQuOTA4LDQuOTA4IDAgMCAwIC0xLjU4LDIuMTc4IDUuOTg0LDUuOTg0IDAgMCA + wIC0wLjAwMyw0LjA1IGMgMC4yNDIsMC42NSAwLjYzLDEuMjM3IDEuMTM2LDEuNzE0IDAuNDM3LDAuNDIyIDAuOTMyLDAuNzggMS40NywxLjA2NSAwLjcwOCwwLjM4IDEuNDU4LDAuNjc1IDIuMjM1LDAuODc4IDAuMjU3LDAuMDc3IDAuNTEyLDAuMTU4IDAuNzY2LDAuMjQzIGwgMC4zODUsMC4xNDEgMC4xMSwwLjA0NSBjIDAuMzgsMC4xMzYgMC43MjYsMC4zNSAxLjAxOCwwLjYyOCAwLjIwMiwwLjE5IDAuMzU4LDAuNDIzIDAuNDU1LDAuNjgzIDAuMDYsMC4yMzcgMC4wN + jEsMC40ODUgMC4wMDMsMC43MjMgYSAxLjUzNiwxLjUzNiAwIDAgMSAtMC43NDQsMC44OTIgMy42OTEsMy42OTEgMCAwIDEgLTEuMjM5LDAuMzg3IDksOSAwIDAgMSAtMS45MiwwLjA5NyAyMS45NzMsMjEuOTczIDAgMCAxIC0yLjUwNywtMC4zMzQgYyAtMC40MzMsLTAuMDkgLTAuODY0LC0wLjE5IC0xLjI5MSwtMC4zMDMgeiBtIC0xMS4xNDQsNC40ODIgaCA0LjczIFYgMzcuODQ2IGggLTQuNzMgeiBNIDg1LjMwNSw0My4zODYgYSA0LjkzNCw0LjkzNCAwIDEgMSA2LjE + 1Nyw3LjcxMSA0LjkzNCw0LjkzNCAwIDAgMSAtNi4xNTcsLTcuNzEgbSAtNi44NjcsMy44NDggYSA5Ljg3LDkuODcgMCAwIDAgMTIuMDAyLDkuNDg1IDkuNjI5LDkuNjI5IDAgMCAwIDMuMTU3LC0xNy43MjkgOS45MzQsOS45MzQgMCAwIDAgLTE1LjE2LDguMjQ0IiBpZD0icGF0aDIiLz48dXNlIGhyZWY9IiNiYXJfc2hvcnQiIHg9IjAiIGlkPSJ1c2UzIi8+PHVzZSBocmVmPSIjYmFyX3RhbGwiIHg9IjAiIGlkPSJ1c2U0Ii8+PHVzZSBocmVmPSIjYmFyX2dyYW5kZSIge + D0iMCIgaWQ9InVzZTUiLz48dXNlIGhyZWY9IiNiYXJfdGFsbCIgeD0iMjUuODc1IiBpZD0idXNlNiIvPjx1c2UgaHJlZj0iI2Jhcl9zaG9ydCIgeD0iNTEuNzUiIGlkPSJ1c2U3Ii8+PHVzZSBocmVmPSIjYmFyX3RhbGwiIHg9IjUxLjc1IiBpZD0idXNlOCIvPjx1c2UgaHJlZj0iI2Jhcl9ncmFuZGUiIHg9IjUxLjc1IiBpZD0idXNlOSIvPjx1c2UgaHJlZj0iI2Jhcl90YWxsIiB4PSI3Ny42MjUiIGlkPSJ1c2UxMCIvPjx1c2UgaHJlZj0iI2Jhcl9zaG9ydCIgeD0iMTAzLjM3NSIgaWQ9InVzZTExIi8+PC9nPjxtZXRhZGF0YSBpZD0ibWV0YWRhdGExMSI+PHJkZjpSREY+PGNjOldvcmsgcmRmOmFib3V0PSIiPjxkYzp0aXRsZT5DaXNjby5jb20gRnJhbmNlPC9kYzp0aXRsZT48L2NjOldvcms+PC9yZGY6UkRGPjwvbWV0YWRhdGE+PC9zdmc+Cg==0 + Brand + Cisco + + + Dell + image/svg+xmlicons8-dell.svgPD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNDggNDgiIHdpZHRoPSI0OHB4IiBoZWlnaHQ9IjQ4cHgiPjxwYXRoIGZpbGw9IiMwMjg4ZDEiIGQ9Ik0yNCw0QzEyLjk1Niw0LDQsMTIuOTU2LDQsMjRzOC45NTYsMjAsMjAsMjBzMjAtOC45NTYsMjAtMjBTMzUuMDQ0LDQsMjQs + NHogTTI0LDQxYy05LjM5MSwwLTE3LTcuNjA5LTE3LTE3UzE0LjYwOSw3LDI0LDdzMTcsNy42MDksMTcsMTdTMzMuMzkxLDQxLDI0LDQxeiIvPjxwYXRoIGZpbGw9IiMwMjg4ZDEiIGQ9Ik0zNS42NDEsMjUuNTYzbDIuODQsMC4wMDRsLTAuMDA0LDIuMzk1bC01LjY5MS0wLjAxMmwwLjAxMi04LjE3MmwyLjg1NSwwLjAwNEwzNS42NDEsMjUuNTYzeiBNMjYuMzQsMjUuMTAybC00LjY5OSwzLjY4NGwtNC4yODUtMy4zNzljLTAuNjIxLDEuNDg0LTIuMTA5LDIuNTItMy44Mz + YsMi41MTZsLTMuNjY0LTAuMDA0bDAuMDA4LTguMTcybDMuNjY4LDAuMDA0YzEuOTI2LDAuMDA0LDMuMzA5LDEuMjIzLDMuODI4LDIuNTMxbDQuMjk3LTMuMzY3bDEuNTg2LDEuMjVsLTMuOTM0LDMuMDg2bDAuNzU0LDAuNTk0bDMuOTM0LTMuMDg2bDEuNTksMS4yNTRsLTMuOTM0LDMuMDgybDAuNzUsMC41OTRsMy45NDEtMy4wODJsMC4wMDQtMi44MzZsMi44NTIsMC4wMDRsLTAuMDA4LDUuNzgxbDIuODQsMC4wMDRsLTAuMDA0LDIuMzkxbC01LjY5MS0wLjAwOEwyNi4zNCwyNS4xMDJ6IE0xNS4wMTIsMjMuODRjMC0xLjExMy0wLjczLTEuNzQyLTEuNzctMS43NDJoLTAuNjM3bC0wLjAwNCwzLjQ3N2gwLjYyMUMxNC4xODQsMjUuNTc0LDE1LjAxMiwyNS4wNTEsMTUuMDEyLDIzLjg0Ii8+PC9zdmc+Cg==0 + Brand + Dell + + + HP Inc + image/svg+xmlicons8-hp.svgPD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNDggNDgiIHdpZHRoPSI0OHB4IiBoZWlnaHQ9IjQ4cHgiPjxwYXRoIGZpbGw9IiNmZmYiIGQ9Ik0yNCA0QTIwIDIwIDAgMSAwIDI0IDQ0QTIwIDIwIDAgMSAwIDI0IDRaIi8+PHBhdGggZmlsbD0iIzE5NzZkMiIgZD0iTTI0LDQzLj + k5N2MtMC4xOTksMC0wLjY1MiwwLjAwNi0wLjg1LDBsNC0xMC45OTloNS42MjVjMC45ODcsMCwyLjA3MS0wLjc1OSwyLjQwOS0xLjY4Nmw0Ljc0OC0xMi42ODdjMC43MjUtMS45OTUtMC40MTctMy42MjYtMi41MzktMy42MjZoLTcuODA0bC02LjUxOCwxOC4yNTdoLTAuMDAybC0zLjcxMiwxMC4xOThDMTAuNTUsNDEuMzYxLDQsMzMuNDQ1LDQsMjMuOTk5YzAtOS4xNzQsNi4xNzgtMTYuOTA1LDE0LjYtMTkuMjYxbC0zLjgzLDEwLjUyNmgtMC4wMDFMOC4xNSwzMi45OTho + NC4yMzlsNS41NzYtMTQuOTk5aDMuMTg1bC01LjU3NiwxNC45OTlsMy45MTksMC4wMDFsNS40MzgtMTQuMzc0YzAuNzI2LTEuOTk1LTAuNDE2LTMuNjI2LTIuNTM2LTMuNjI2SDE5LjE1bDMuOTUxLTEwLjk3OEMyMy4zOTksNC4wMDgsMjMuNjk5LDQsMjQsNGMxMS4wNDYsMCwyMCw4Ljk1MywyMCwxOS45OTlTMzUuMDQ2LDQzLjk5NywyNCw0My45OTd6IE0zNi4xNSwxNy45OTloLTMuMTg1bC00LjUwOSwxMS45OTloMy4xODVMMzYuMTUsMTcuOTk5eiIvPjwvc3ZnPgo=0 + Brand + HP Inc + + + HPE + image/svg+xmlicon-hpe.svgPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiIHhtbG5zOnNvZGlwb2RpPSJodHRwOi8vc29kaXBvZGkuc291cmNlZm9yZ2UubmV0L0RURC9zb2RpcG9kaS0wLmR0ZCIgeG1sbnM9Imh0dHA6Ly93d3c + udzMub3JnLzIwMDAvc3ZnIiB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjAiIGlkPSJrYXRtYW5fMSIgeD0iMHB4IiB5PSIwcHgiIHZpZXdCb3g9IjAgMCA2MzAgNjMwIiB4bWw6c3BhY2U9InByZXNlcnZlIiBzb2RpcG9kaTpkb2NuYW1lPSJpY29uLWhwZS5zdmciIHdpZHRoPSI2MzAiIGhlaWdodD0iNjMwIiBpbmtzY2FwZTp2ZXJzaW9uPSIxLjQuMyAoMGQxNWY3NTA0MiwgMjAyNS0xMi0yNSkiPjxkZWZzIGlkPSJkZWZzM + iIvPjxzb2RpcG9kaTpuYW1lZHZpZXcgaWQ9Im5hbWVkdmlldzIiIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIgYm9yZGVyY29sb3I9IiMwMDAwMDAiIGJvcmRlcm9wYWNpdHk9IjAuMjUiIGlua3NjYXBlOnNob3dwYWdlc2hhZG93PSIyIiBpbmtzY2FwZTpwYWdlb3BhY2l0eT0iMC4wIiBpbmtzY2FwZTpwYWdlY2hlY2tlcmJvYXJkPSIwIiBpbmtzY2FwZTpkZXNrY29sb3I9IiNkMWQxZDEiIHNob3dndWlkZXM9InRydWUiIGlua3NjYXBlOnpvb209IjAuNjkwNTUxNSIgaW5rc2N + hcGU6Y3g9Ii0yMTcuOTQxNzUiIGlua3NjYXBlOmN5PSIyNzUuMTQyNCIgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIyNTYwIiBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSIxMzYwIiBpbmtzY2FwZTp3aW5kb3cteD0iMCIgaW5rc2NhcGU6d2luZG93LXk9IjAiIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjEiIGlua3NjYXBlOmN1cnJlbnQtbGF5ZXI9ImthdG1hbl8xIj48c29kaXBvZGk6Z3VpZGUgcG9zaXRpb249IjE5Ny42NjI0NCwzMTQuNDg4NDgiIG9yaWVudGF0a + W9uPSIwLC0xIiBpZD0iZ3VpZGUyIiBpbmtzY2FwZTpsb2NrZWQ9ImZhbHNlIi8+PC9zb2RpcG9kaTpuYW1lZHZpZXc+CjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyIgaWQ9InN0eWxlMSI+Cgkuc3Qwe2ZpbGw6bm9uZTtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MzY7fQoJLnN0MXtmaWxsOm5vbmU7c3Ryb2tlOiMwM0E4ODM7c3Ryb2tlLXdpZHRoOjM2O30KPC9zdHlsZT4KPHBhdGggY2xhc3M9InN0MCIgZD0ibSAxOC41MTE5ODcsNDA1LjkzMDEyIHYgLTE4MCBtIDE + 1NC4wMDAwMDMsMTgwIHYgLTE4MCBtIC0xNTQuMDAwMDAzLDg5IEggMTU1LjUxMTk5IG0gOTUsOTEgdiAtMTgwIG0gMCwxOCBoIDEwMiBjIDI3LjYsMCA1MCwyMi40IDUwLDUwIDAsMjcuNiAtMjIuNCw1MCAtNTAsNTAgaCAtMTAyIG0gMjIyLC02NyB2IC0zMyBoIDE1OCIgaWQ9InBhdGgxIi8+CjxwYXRoIGNsYXNzPSJzdDEiIGQ9Im0gNjMwLjUxMTk5LDM4Ny45MzAxMiBoIC0xNTggdiAtNzYgaCAxNTgiIGlkPSJwYXRoMiIvPgo8L3N2Zz4K0 + Brand + HPE + + + IBM + image/svg+xmlicons8-ibm.svgPD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNDggNDgiIHdpZHRoPSI0OHB4IiBoZWlnaHQ9IjQ4cHgiPjxwYXRoIGZpbGw9IiMzZjUxYjUiIGQ9Ik00OCAxNkw0OCAxNCA0MC40NjkgMTQgMzkuODA5IDE2ek0zMyAzMUwzMyAyOSAyOSAyOSAyNyAyOSAyNyAzMXpNMzkuNzY2I + DI4TDQwLjUxIDI2IDM0LjUxIDI2IDM1LjI2NiAyOHpNMjkgMjZIMzNWMjhIMjl6TTI5IDIzSDMzVjI1SDI5ek00MiAyOUw0MiAzMSA0OCAzMSA0OCAyOSA0NiAyOXpNMzYuMTgxIDE5TDM1LjUyMSAxNyAyNyAxNyAyNyAxOSAyOSAxOXpNMzcuMTcgMjJMMzYuNTEgMjAgMjkgMjAgMjkgMjJ6TTMzLjM3OCAyM0wzNC4xMzMgMjUgNDAuODgzIDI1IDQxLjYyOCAyM3pNNDIgMjNINDZWMjVINDJ6TTI3IDMySDMzVjM0SDI3ek0zNS4xOTEgMTZMMzQuNTMxIDE0IDI3IDE0IDI + 3IDE2ek0zNi43NzYgMzJMMzcuNTMxIDM0IDM4LjI3NiAzMnpNNDIgMzJINDhWMzRINDJ6TTM5LjQ3OSAxN0wzOC44MTkgMTkgNDYgMTkgNDggMTkgNDggMTd6TTM5LjM5MyAyOUwzNS42NDMgMjkgMzYuMzk4IDMxIDM4LjY0OCAzMXpNNDIgMjZINDZWMjhINDJ6TTM4LjQ5IDIwTDM3LjgzIDIyIDQ2IDIyIDQ2IDIwek0wIDE0SDhWMTZIMHpNMCAxN0g4VjE5SDB6TTIgMjBINlYyMkgyek0yIDIzSDZWMjVIMnpNMiAyNkg2VjI4SDJ6TTAgMjlIOFYzMUgwek0wIDMySDhWM + zRIMHpNMTAgMTdIMThWMTlIMTB6TTI0Ljk3NyAxNmMtLjkxMy0xLjIwOC0yLjM0Ny0yLTMuOTc3LTJIMTB2Mmg3LjAyM0gyNC45Nzd6Ii8+PHBhdGggZmlsbD0iIzNmNTFiNSIgZD0iTTI1LjU3OCAxN2gtOS4xMzFDMTYuMTcxIDE3LjYxMyAxNiAxOC4yODMgMTYgMTloMTBDMjYgMTguMjg4IDI1Ljg0NiAxNy42MTMgMjUuNTc4IDE3ek0yMy45NzUgMjNIMTJ2MmgxMS45NzNjLS44MzMtLjYyLTEuODU0LTEtMi45NzMtMUMyMi4xMTkgMjQgMjMuMTQyIDIzLjYyMSAyMy4 + 5NzUgMjN6TTE3LjAyMyAzMkgxMHYyaDExYzEuNjMgMCAzLjA2NS0uNzkyIDMuOTc3LTJIMTcuMDIzek0xOCAyOWgtMi02djJoNi40NDdIMThoNy41NzhDMjUuODQ2IDMwLjM4NyAyNiAyOS43MTIgMjYgMjlIMTh6TTIxIDIwYzAgMCAwIC4wODMgMCAxcy0xIDEtMSAxaDQuOTc5Yy40NDEtLjU4NC43Ny0xLjI1Ny45MjEtMkgyMXpNMTIgMjBIMTdWMjJIMTJ6Ii8+PGc+PHBhdGggZmlsbD0iIzNmNTFiNSIgZD0iTTIxIDI4aDQuODg1Yy0uMTU2LS43MzgtLjQ2Ny0xLjQxOC0uOTA3LTJIMjBjMCAwIDEgLjE2NyAxIDFTMjEgMjggMjEgMjh6TTEyIDI2SDE3VjI4SDEyeiIvPjwvZz48L3N2Zz4K0 + Brand + IBM + + + Lenovo + image/svg+xmlicons8-lenovo.svgPD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNDggNDgiIHdpZHRoPSI0OHB4IiBoZWlnaHQ9IjQ4cHgiPjxyZWN0IHdpZHRoPSI0OCIgaGVpZ2h0PSIxNiIgeT0iMTYiIGZpbGw9IiNmZjE3NDQiLz48cGF0aCBmaWxsPSIjZmZmIiBkPSJNMTEuOTM1LDI2LjA2MmMwLjM3LD + AuMzQxLDAuNzgyLDAuNDUsMS4yMjcsMC40NzhjMC42NDUsMC4wMzksMS4yMTctMC4xNTYsMS43MjQtMC41NDYgYzAuMTI0LTAuMDk2LDAuMTYzLTAuMTI2LDAuMTYzLTAuMTI2czAuNzc3LDAuNjA5LDEuMDk3LDAuODU1Yy0wLjI2MSwwLjMwOS0wLjU2NywwLjUyMS0wLjkwMSwwLjY5MiBjLTEuMTAzLDAuNTY1LTIuMjQ5LDAuNjg3LTMuNDI0LDAuMjY0Yy0xLjM0Ni0wLjQ4NS0yLjEzMS0xLjY5My0yLjA1OS0zLjExN2MwLjA3My0xLjQ0MSwxLjAwNS0yLjYwOCwyLjM5 + Mi0yLjk0NCBjMS4wNjQtMC4yNTcsMi4wODQtMC4xNDMsMi45OCwwLjUzOWMwLjY1MSwwLjQ5NiwxLjAwMSwxLjI4LDEuMTQ3LDIuMDY4YzAsMC0yLjU5NSwxLjExLTMuNzk1LDEuNjA2IEMxMi4zMTMsMjUuOTAzLDEyLjE0MSwyNS45NzUsMTEuOTM1LDI2LjA2MnogTTExLjQ3MiwyNC45MjhjMC45NjktMC40MDEsMS45MzUtMC44MDEsMi45MDEtMS4yMDEgYy0wLjMzNC0wLjcyMi0xLjA5Ni0xLjAxNy0xLjg2Ni0wLjc0OEMxMS43NTgsMjMuMjQsMTEuMjgsMjQuMTI0LD + ExLjQ3MiwyNC45Mjh6Ii8+PHBhdGggZmlsbD0iI2ZmZiIgZD0iTTI3LjA3NiwyNy45MzRjLTEuNjMyLTAuMDE3LTIuOTU2LTEuMDY4LTMuMjYxLTIuNmMtMC4zNy0xLjg1MiwwLjk2OS0zLjYzMywyLjg2LTMuODA4IGMxLjI4MS0wLjExOCwyLjM3MywwLjI1NCwzLjE1NSwxLjNjMS40NTEsMS45NDEsMC4yMiw0Ljc1Ny0yLjE5Myw1LjA1NUMyNy40NSwyNy45MDUsMjcuMjYzLDI3LjkxNywyNy4wNzYsMjcuOTM0eiBNMjcuMTEsMjYuNDM0IGMwLjkyOSwwLjAwMiwxLjYy + Mi0wLjcyMywxLjYyOC0xLjcwNGMwLjAwNi0wLjk3LTAuNzI0LTEuNzQyLTEuNjQ5LTEuNzQ1Yy0wLjkzNi0wLjAwMy0xLjYzMSwwLjczNC0xLjYyOCwxLjcyNiBDMjUuNDY1LDI1LjY3NSwyNi4xODksMjYuNDMyLDI3LjExLDI2LjQzNHoiLz48cGF0aCBmaWxsPSIjZmZmIiBkPSJNNDAuNjI0LDI3LjkzNGMtMS42MzItMC4wMTctMi45NTYtMS4wNjgtMy4yNjEtMi42Yy0wLjM3LTEuODUyLDAuOTY5LTMuNjMzLDIuODYtMy44MDggYzEuMjgxLTAuMTE4LDIuMzczLDAuMj + U0LDMuMTU1LDEuM2MxLjQ1MSwxLjk0MSwwLjIyLDQuNzU3LTIuMTkzLDUuMDU1QzQwLjk5OCwyNy45MDUsNDAuODExLDI3LjkxNyw0MC42MjQsMjcuOTM0eiBNNDAuNjU4LDI2LjQzNGMwLjkyOSwwLjAwMiwxLjYyMy0wLjcyMywxLjYyOC0xLjcwNGMwLjAwNi0wLjk3LTAuNzI0LTEuNzQyLTEuNjQ5LTEuNzQ1Yy0wLjkzNi0wLjAwMy0xLjYzMSwwLjczNC0xLjYyOCwxLjcyNiBDMzkuMDEzLDI1LjY3NSwzOS43MzcsMjYuNDMyLDQwLjY1OCwyNi40MzR6Ii8+PHBhdGgg + ZmlsbD0iI2ZmZiIgZD0iTTIxLjM3NywyNy45ODdjMC0wLjA5NSwwLjAwMS0yLjU4NywwLTMuNjYzYy0wLjAwMS0wLjc1OS0wLjYwNS0xLjMyNy0xLjQxNC0xLjMzMSBjLTAuNzk0LTAuMDA1LTEuMzgzLDAuNTYtMS4zODQsMS4zMzJjLTAuMDAxLDEuMDc2LDAsMy42NzksMCwzLjY3OWwtMS43NDEsMC4wMDJsMC4wMDctNi4zNzhjMCwwLDEuMTY4LTAuMDE4LDEuNzIyLTAuMDE4IGMwLDAuMjY0LTAuMDA2LDAuODMyLTAuMDA2LDAuODMyczAuMTM4LTAuMTI4LDAuMTgxLT + AuMTcxYzEuMTU3LTEuMTc0LDMuMjI2LTAuOTczLDQuMDMxLDAuMzkxIGMwLjIyMywwLjM3OCwwLjMzOCwwLjc4OSwwLjM0LDEuMjIzYzAuMDA4LDEuMjY0LDAuMDAzLDQuMTA0LDAuMDAzLDQuMTA0UzIxLjk2NCwyNy45ODcsMjEuMzc3LDI3Ljk4N3oiLz48cGF0aCBmaWxsPSIjZmZmIiBkPSJNMzAuMTY0LDIxLjYwOGMwLjY0MiwwLDEuOTY0LDAuMDE1LDEuOTY0LDAuMDE1czEuNDc4LDQuMDI0LDEuNTI2LDQuMTQ5IGMwLjExNS0wLjMxMSwxLjIwOC0zLjI5LDEuNTIx + LTQuMTc0YzAuNjQ2LDAuMDE4LDEuMjg4LDAuMDEsMS45NywwLjAxYy0wLjAyOSwwLjA4NC0yLjU2Miw2LjM5OC0yLjU2Miw2LjM5OGwtMS44NzYtMC4wMDMgQzMxLjkwNSwyNi4wNDIsMzAuMTkxLDIxLjY5MiwzMC4xNjQsMjEuNjA4eiIvPjxwYXRoIGZpbGw9IiNmZmYiIGQ9Ik01Ljc2NywyNi4zOTNjMC4xMDQsMCwzLjg2OCwwLjAxMSwzLjg2OCwwLjAxMWwtMC4wMDIsMS41ODFMNCwyNy45ODl2LTguMDczaDEuNzcgQzUuNzcsMTkuOTE2LDUuNzY3LDI2LjI4NCw1Ljc2NywyNi4zOTN6Ii8+PC9zdmc+Cg==0 + Brand + Lenovo + + + Razer + image/svg+xmlicons8-razer.svgPD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNDggNDgiIHdpZHRoPSI0OHB4IiBoZWlnaHQ9IjQ4cHgiPjxwYXRoIGZpbGw9IiM2NGRkMTciIGQ9Ik0yNiwyMGMwLjEsMCwwLjIsMCwwLjMsMGMwLjMtMC4xLDAuNS0wLjMsMC42LTAuNWMwLjEtMC4yLDAuMS0wLjUsMC4xLTA + uOGMtMC4yLTAuNi0xLTEuOC0yLTIuNCBjMCwwLjcsMCwxLjMsMCwxLjljMCwwLjUsMCwxLDAsMS4yYzAuMSwwLjIsMC4zLDAuNCwwLjUsMC42QzI1LjcsMjAsMjUuOCwyMCwyNiwyMCBNMjkuNCwyM2MwLjcsMCwxLjYtMC4xLDIuMy0wLjUgYy0wLjUtMC4zLTEtMC42LTEuNS0wLjljLTAuNC0wLjMtMC45LTAuNi0xLjEtMC42YzAsMC0wLjEsMC0wLjEsMGMtMC4yLDAtMC40LDAuMS0wLjYsMC4yYy0wLjIsMC4xLTAuNCwwLjQtMC40LDAuNiBjLTAuMSwwLjUsMC4zLDEuM + SwwLjgsMS4yQzI5LDIzLDI5LjIsMjMsMjkuNCwyMyBNMjMsMjQuOWMwLjUtMC4yLDEtMC40LDEuNS0wLjZjMC41LTAuMiwxLTAuNCwxLjItMC41YzAuMi0wLjIsMC4zLTAuNCwwLjMtMC43IGMwLTAuMy0wLjEtMC41LTAuMy0wLjdDMjUuNiwyMi4xLDI1LjMsMjIsMjUsMjJjLTAuMiwwLTAuNSwwLjEtMC43LDAuM0MyMy45LDIyLjYsMjMuMiwyMy44LDIzLDI0LjkgTTQxLjUsMSBjLTAuNywwLTEuNCwwLjUtMS41LDEuM2MwLDAsMCwwLDAsMEMzOS43LDIuMSwzOS40LDI + sMzksMmMtMS43LDAtMi45LDAuMi0zLjYsMC43QzM0LjUsMy4yLDM0LDQuMSwzNCw1YzAsMC4xLDAsMC4xLDAsMC4yIEMzMy42LDUuMSwzMy4xLDUsMzIuNyw1Yy0xLjMsMC0yLjQsMC43LTMuMSwyQzI5LjIsNy43LDI5LDguNCwyOSw5LjJjMCwyLjYsMi4yLDQuNiw0LjUsNi42YzIuNywyLjQsMy45LDMuOCwzLjMsNC44IGMtMC4yLDAuNC0wLjQsMC40LTAuNCwwLjRjLTAuMSwwLTAuMiwwLTAuMywwYy0wLjEsMC0wLjMsMC0wLjUtMC4xYzAtMC42LTAuMS0xLjEtMC4yL + TEuNmMtMC4yLTAuNi0wLjUtMS4yLTEtMS43IGMtMC40LTAuNS0xLTAuNy0xLjUtMC45Yy0wLjEsMC0wLjItMC4xLTAuNC0wLjFjLTAuMywwLTAuNywwLjItMC44LDAuNWMtMC4zLDAuNC0wLjIsMC45LDAuMiwxLjNjMC4yLDAuMiwwLjQsMC40LDAuNSwwLjYgYzAuMSwwLjIsMC4xLDAuMywwLjEsMC41Yy0wLjItMC4xLTAuNS0wLjMtMC43LTAuNGMtMC44LTAuNS0xLjQtMC45LTEuOS0xYzAtMC4xLTAuMS0wLjItMC4xLTAuM2MtMC41LTEuNS0yLjEtMy43LTQuMy00LjU + gYy0xLTMuNS0zLjMtNC4zLTUuMS00LjNjLTQuNiwwLTUuNCw0LjktNiw4LjVjLTAuMiwxLjQtMC43LDQtMS4zLDQuNWMwLTAuMi0wLjEtMC41LTAuMS0xQzEzLDE5LjksMTIuNywxNywxMCwxNyBjLTEuNiwwLTIuNCwxLjEtMi44LDEuN2MtMC4yLTAuMi0wLjMtMC40LTAuNC0wLjZjLTAuMy0wLjYtMS0xLjEtMS43LTEuMUM1LjEsMTYuOSw1LDE2LjcsNSwxNi41QzUsMTUuNyw0LjMsMTUsMy41LDE1IGMtMC43LDAtMS4yLDAuNC0xLjQsMS4xQzEuNCwxNi4zLDEsMTYuO + CwxLDE3LjVDMSwxOC4zLDEuNywxOSwyLjUsMTljMC4xLDAsMC4yLDAsMC4zLDBDMi45LDE5LjEsMywxOS4xLDMsMTkuMiBjMCwwLjIsMC4xLDAuNSwwLjIsMC43YzEsMS45LDIuNSwyLjcsMywyLjlDNi42LDIyLjksNywyMyw3LjQsMjNjMC43LDAsMS4zLTAuMiwxLjgtMC41QzkuNSwyNCwxMC4zLDI2LDEzLDI2IGM0LjEsMCw0LjktNC42LDUuNC03LjljMC42LTMuNCwxLTUuMSwyLTUuMWMwLjMsMCwwLjcsMCwxLjEsMC45Yy0wLjQsMC4yLTAuNywwLjUtMSwwLjhjLTA + uNSwwLjUtMC44LDEuMS0xLDEuNyBjLTAuMiwwLjYtMC4xLDEuMi0wLjEsMS43YzAuMSwwLjUsMC41LDAuOCwwLjksMC45YzAsMCwwLDAsMC4xLDBjMC41LDAsMC45LTAuMywxLTAuOGMwLjEtMC4zLDAuMi0wLjYsMC4zLTAuOCBjMC4xLTAuMSwwLjItMC4yLDAuMy0wLjNjMCwwLjMsMCwwLjYsMCwwLjljMCwwLjksMCwxLjUsMC4xLDJjLTEsMS0yLjIsMy0yLjIsNS4yYy0xLjMsMC45LTIuMiwxLjktMi43LDNjLTAuNSwxLjItMC41LDIuNSwwLjEsMy43IGMwLjgsMS45L + DIuNSwyLjksNC45LDIuOWMxLjgsMCwzLjgtMC41LDUuNy0xLjFjMS43LTAuNSwzLjMtMC45LDQuMy0wLjljMC4yLDAsMC40LDAsMC42LDAuMWMtMC4yLDAuMS0wLjUsMC4zLTEsMC42IGMtMS4xLDAuNi0zLjYsMi0yLjUsNC41YzAuNywxLjYsMi41LDEuOCwzLjYsMS44bDAuMSwwYzAsMCwwLDAsMCwwYy0wLjEsMC4yLTAuMiwwLjMtMC40LDAuNmMtMC40LDAuNC0wLjYsMC44LTAuNiwxLjMgYy0wLjEsMC0wLjMsMC4xLTAuNSwwLjFjLTAuOCwwLTEuNSwwLjctMS41LDE + uNWMwLDAuNywwLjQsMS4yLDEuMSwxLjRjMC4yLDAuNiwwLjgsMS4xLDEuNCwxLjFjMC44LDAsMS41LTAuNywxLjUtMS41bDAtMC4zIGMwLjEtMC4xLDAuMS0wLjEsMC4yLTAuMmMwLjUsMCwwLjktMC4yLDEuMi0wLjZjMS43LTEuNywxLjYtMy4zLDEuNi00LjFjMC0xLjMtMC45LTIuNC0yLTIuOWMxLjMtMC45LDIuNy0yLjUsMS42LTQuOCBjLTAuOC0xLjctMi4yLTIuNi00LjQtMi42Yy0xLjcsMC0zLjUsMC41LTUuMywxYy0xLjgsMC41LTMuNCwwLjktNC42LDAuOWMtM + SwwLTEuMS0wLjMtMS4yLTAuNUMyMSwzMC4xLDIxLDI5LjksMjEsMjkuOCBjMC4xLTAuMiwwLjMtMC41LDAuOC0wLjljMC40LDAuNCwwLjksMC42LDEuMywwLjhjMC40LDAuMiwwLjksMC4zLDEuNCwwLjNjMC4yLDAsMC40LDAsMC42LTAuMWMwLjYtMC4xLDEuMi0wLjQsMS42LTAuNyBjMC40LTAuMywwLjYtMC44LDAuNC0xLjJjLTAuMS0wLjQtMC41LTAuNi0wLjktMC42Yy0wLjEsMC0wLjEsMC0wLjIsMGMtMC4yLDAtMC40LDAuMS0wLjYsMC4xYy0wLjEsMC0wLjIsMC0 + wLjIsMCBjLTAuMiwwLTAuMy0wLjEtMC40LTAuMmMwLjItMC4xLDAuNS0wLjIsMC43LTAuM2MxLTAuNCwxLjYtMC42LDItMWMwLjEtMC4xLDAuMS0wLjEsMC4yLTAuMmMwLjEsMCwwLjMsMC4xLDAuNCwwLjEgQzI4LjYsMjYsMjksMjYsMjkuNCwyNmMwLjksMCwyLjktMC4xLDQuNS0xLjRjMC44LDAuMiwxLjUsMC40LDIuMiwwLjRjMC40LDAsMC45LTAuMSwxLjMtMC4yYzEuMi0wLjMsMi4zLTEuMSwyLjktMi4zIGMyLjItMy45LTEuMy03LjEtNC4yLTkuN0MzNC45LDExL + jcsMzMsMTAsMzMsOS4xYzAsMCwwLDAsMC0wLjFjMC4yLDAuMSwwLjQsMC4xLDAuOCwwLjNjMC42LDAuMiwxLjUsMC42LDIuNCwwLjYgYzEuMSwwLDEuOS0wLjUsMi41LTEuNWMwLjYtMSwwLjQtMS45LDAuMS0yLjVjMC4xLDAsMC4yLDAsMC4zLDBjMC42LDAsMS4yLTAuMywxLjYtMC44QzQxLjMsNS4xLDQyLDUsNDIuNSw1QzQzLjMsNSw0NCw0LjMsNDQsMy41IGMwLTAuNy0wLjQtMS4yLTEuMS0xLjRDNDIuNywxLjQsNDIuMiwxLDQxLjUsMUw0MS41LDF6Ii8+PHBhdGg + gZD0iTTEzLDI1Yy0yLjYsMC0yLjgtMi41LTIuOS0zLjhjMC0wLjMtMC4xLTAuOS0wLjItMS4xYy0wLjEsMC4xLTAuMSwwLjItMC4yLDAuM2MtMC4xLDAuMS0wLjIsMC4zLTAuMywwLjUgYy0wLjYsMS0xLjksMS40LTIuOSwxYy0wLjgtMC4zLTEuOC0xLjEtMi41LTIuNGMtMC4yLTAuNSwwLTEuMSwwLjQtMS4zYzAuNS0wLjIsMS4xLDAsMS4zLDAuNGMwLjQsMC43LDEsMS4zLDEuNCwxLjQgYzAuMiwwLjEsMC40LDAsMC41LTAuMmMwLjEtMC4xLDAuMi0wLjMsMC4yLTAuN + GMwLjMtMC42LDAuOC0xLjQsMi0xLjRjMS44LDAsMiwxLjksMi4xLDNjMC4yLDEuOCwwLjQsMiwwLjksMiBjMS41LDAsMS45LTIuMSwyLjUtNS40YzAuNi0zLjQsMS4zLTcuNiw1LTcuNmMyLjcsMCwzLjgsMS45LDQuMiw0LjFjMi4xLDAuNCwzLjcsMi43LDQuMSw0YzAuMiwwLjgsMC4yLDEuNi0wLjIsMi4zcy0xLDEuMi0xLjcsMS41IGMtMC44LDAuMi0xLjYsMC4yLTIuMy0wLjJjLTAuNy0wLjQtMS4yLTEtMS41LTEuN0MyMywxOS42LDIzLDE5LjEsMjMsMTguMmMwLTM + uNy0wLjQtNi4yLTIuNi02LjJjLTEuOSwwLTIuNCwyLjQtMyw2IEMxNi45LDIxLjMsMTYuMywyNSwxMywyNXogTTI1LDE2LjNjMCwwLjcsMCwxLjMsMCwxLjljMCwwLjUsMCwxLDAsMS4yYzAuMSwwLjIsMC4zLDAuNCwwLjUsMC42YzAuMiwwLjEsMC41LDAuMSwwLjgsMC4xIGMwLjMtMC4xLDAuNS0wLjMsMC42LTAuNWMwLjEtMC4yLDAuMS0wLjUsMC4xLTAuOEMyNi44LDE4LjEsMjYsMTYuOSwyNSwxNi4zeiIvPjxwYXRoIGQ9Ik0yNCAxNmMtLjMtLjEtLjctLjEtMS4xL + S4xLS40IDAtLjcuMS0xLjEuMi0uMy4xLS42LjQtLjkuNy0uMy4zLS40LjctLjUgMS4xLS4xLS40LS4xLS45IDAtMS40LjEtLjUuNC0uOS43LTEuMy40LS40LjgtLjcgMS4yLS45LjUtLjIuOS0uNCAxLjUtLjVsLjEgMGMuNi0uMSAxLjEuMyAxLjIuOFMyNSAxNS45IDI0LjUgMTZDMjQuMyAxNiAyNC4xIDE2IDI0IDE2ek0zLjUgMTguMWMtLjEgMC0uMSAwLS4yIDBDMy4xIDE4IDIuOCAxOCAyLjUgMTggMi4yIDE4IDIgMTcuOCAyIDE3LjVTMi4yIDE3IDIuNSAxN2MuNSA + wIC44IDAgMS4yLjJDNCAxNy4zIDQuMSAxNy42IDQgMTcuOCAzLjkgMTggMy43IDE4LjEgMy41IDE4LjF6Ii8+PHBhdGggZD0iTTQuNSAxOWMtLjEgMC0uMSAwLS4yLS4xLS4xIDAtMS4zLS43LTEuMy0yLjRDMyAxNi4yIDMuMiAxNiAzLjUgMTZTNCAxNi4yIDQgMTYuNWMwIDEuMS43IDEuNS43IDEuNi4yLjEuMy40LjIuN0M0LjkgMTguOSA0LjcgMTkgNC41IDE5ek0zNCA0M2MtLjMgMC0uNS0uMS0uNy0uMy0uNC0uNC0uNC0xIDAtMS40LjctLjcuNy0xLjQuNy0xLjggM + C0uMi0uMi0uMy0uNC0uNC0uMiAwLS40IDAtLjctLjEtMS0uMS0yLjMtLjItMi44LTEuMi0uNy0xLjcgMS0yLjYgMi4xLTMuMiAxLjctLjkgMS45LTEuMiAxLjYtMS44LS42LTEuMy0yLjgtLjgtNi4yLjEtMy43IDEtNy44IDIuMi05LjMtMS4zLS40LTEtLjUtMi0uMS0yLjkuNS0xLjIgMS42LTIuMSAyLjgtMi44LS4zLTIuMSAxLTQuMyAyLTUuMSAxLjItMS4xIDMuMS0xIDQuMi4yIDEuMSAxLjIgMSAzLjEtLjIgNC4yLS4zLjMtLjguNS0xLjcuOS0uNi4zLTEuNS42LTI + uMyAxLS4xLjEtLjIuMi0uMy4yLS4xIDAtLjEuMS0uMi4xLTEgLjYtMiAxLjMtMi4zIDIuMS0uMi40LS4yLjkuMSAxLjQuOCAxLjcgMy4zIDEuMiA3IC4yIDMuNC0uOSA3LjItMiA4LjYgMSAxIDIuMy0xLjIgMy42LTIuNSA0LjMtLjMuMi0uOC40LTEgLjYuMyAwIC42LjEuOS4xLjMgMCAuNiAwIC44LjEgMS4yLjIgMi4xIDEuMiAyLjEgMi4zIDAgLjYuMSAyLTEuMyAzLjNDMzQuNSA0Mi45IDM0LjMgNDMgMzQgNDN6TTI1IDIyYy0uMiAwLS41LjEtLjcuMy0uNC40LTEuM + iAxLjUtMS4zIDIuNi41LS4yIDEtLjQgMS41LS42LjUtLjIgMS0uNCAxLjItLjUuNC0uMy40LTEgMC0xLjRDMjUuNSAyMi4xIDI1LjMgMjIgMjUgMjJ6Ii8+PHBhdGggZD0iTTIzLjIgMjYuMWMwIC4zLjIuNy4zIDEgLjIuMy4zLjYuNi45LjIuMy42LjQgMSAuNS40LjEuOC4xIDEuMiAwLS40LjItLjguNS0xLjIuNS0uNS4xLTEgMC0xLjUtLjItLjUtLjItLjktLjUtMS4zLS44LS40LS40LS43LS43LTEtMS4ybC0uMS0uMWMtLjMtLjUtLjEtMS4xLjQtMS40LjUtLjMgMS4 + xLS4xIDEuNC40QzIzLjIgMjUuOCAyMy4yIDI1LjkgMjMuMiAyNi4xek0zMi41IDQ1Yy0uMyAwLS41LS4yLS41LS41bDAtLjVjMC0uMiAwLS40IDAtLjYgMC0uMy4zLS41LjUtLjUuMyAwIC41LjIuNS41IDAgLjIgMCAuMyAwIC41bDAgLjVDMzMgNDQuOCAzMi44IDQ1IDMyLjUgNDV6Ii8+PHBhdGggZD0iTTMxLjUgNDRjLS4zIDAtLjUtLjItLjUtLjVzLjItLjUuNS0uNWMxLjEgMCAxLjUtLjcgMS42LS43LjEtLjIuNC0uMy43LS4yLjIuMS4zLjQuMi43QzMzLjkgNDIuO + CAzMy4zIDQ0IDMxLjUgNDR6TTI5LjQgMjVjLS40IDAtLjcgMC0xLS4xLTEuNi0uMy0yLjctMS45LTIuNC0zLjUuMi0uOC42LTEuNSAxLjMtMS45LjctLjQgMS41LS42IDIuMy0uNS40LjEuOC4zIDEuNy45LjYuNCAxLjQuOCAyLjIgMS4yIDAgMCAwIDAgMCAwIC4yIDAgLjMgMCAuNS4xLjEuMS4yLjEuMy4yLjkuNCAxLjguNiAyLjQuNC40LS4xLjgtLjQgMS4xLS45IDEtMS43LS44LTMuNS0zLjUtNkMzMiAxMy4xIDMwIDExLjMgMzAgOS4yYzAtLjYuMS0xLjIuNC0xLjd + DMzEuMSA2LjMgMzIgNiAzMi43IDZjLjggMCAxLjYuMyAyLjMuNi4yLjEuNi4yLjguMyAwIDAgMCAwIDAgMC0uMi0uMi0uMy0uNC0uNS0uN0MzNS4xIDUuOCAzNSA1LjQgMzUgNWMwLS42LjMtMS4xLjktMS41QzM2LjYgMy4xIDM4LjEgMyAzOSAzYy42IDAgMSAuNCAxIDFzLS40IDEtMSAxYy0uOCAwLTEuNi4xLTIgLjIgMCAwIDAgMCAwIDAgLjEuMi4yLjQuMy41QzM3LjggNi4yIDM4LjMgNyAzNy44IDhjLS45IDEuNi0yLjUuOS0zLjYuNEMzMy43IDguMiAzMy4xIDggM + zIuNyA4Yy0uMSAwLS4zIDAtLjYuNEMzMiA4LjYgMzIgOC45IDMyIDkuMWMwIDEuMyAxLjggMi45IDMuNSA0LjQgMi43IDIuNCA1LjcgNS4yIDQgOC40LS41IDEtMS4zIDEuNi0yLjMgMS45LTEuMS4zLTIuMy4xLTMuNC0uNEMzMi42IDI0LjYgMzAuOCAyNSAyOS40IDI1ek0yOSAyMWMtLjIgMC0uNC4xLS42LjItLjIuMS0uNC40LS40LjYtLjEuNS4zIDEuMS44IDEuMi41LjEgMS45LjEgMi45LS41LS41LS4zLTEtLjYtMS41LS45LS40LS4zLS45LS42LTEuMS0uNkMyOS4 + xIDIxIDI5LjEgMjEgMjkgMjF6Ii8+PHBhdGggZD0iTTMyLjYgMjEuN2MuMi0uMi40LS42LjYtLjkuMi0uMy4zLS43LjMtMS4xIDAtLjQgMC0uNy0uMi0xLjEtLjEtLjQtLjQtLjctLjgtMSAuNC4yLjguMyAxLjIuNy4zLjMuNi44LjggMS4zLjEuNS4yIDEgLjIgMS41IDAgLjUtLjEgMS0uMyAxLjVsMCAuMWMtLjIuNS0uOC44LTEuMy42cy0uOC0uOC0uNi0xLjNDMzIuNCAyMS45IDMyLjUgMjEuOCAzMi42IDIxLjd6TTQwLjggNC4xYy0uMiAwLS40LS4yLS41LS40IDAtL + jMuMS0uNS40LS42LjEgMCAuMi0uMi4yLS42QzQxIDIuMiA0MS4yIDIgNDEuNSAyUzQyIDIuMiA0MiAyLjVDNDIgMy4zIDQxLjUgNCA0MC44IDQuMSA0MC45IDQuMSA0MC45IDQuMSA0MC44IDQuMXoiLz48cGF0aCBkPSJNMzksNC41Yy0wLjIsMC0wLjQtMC4yLTAuNS0wLjRjLTAuMS0wLjMsMC4xLTAuNSwwLjQtMC42QzM5LDMuNSw0MSwzLDQyLjUsM0M0Mi44LDMsNDMsMy4yLDQzLDMuNVM0Mi44LDQsNDIuNSw0IGMtMS40LDAtMy40LDAuNS0zLjQsMC41QzM5LjEsNC41LDM5LDQuNSwzOSw0LjV6Ii8+PC9zdmc+Cg==0 + Brand + Razer + + + Samsung + image/svg+xmlicons8-samsung.svgPD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNDggNDgiIHdpZHRoPSI0OHB4IiBoZWlnaHQ9IjQ4cHgiPjxwYXRoIGZpbGw9IiMwZDQ3YTEiIGQ9Ik00Ny45NywxOS44MjZjMC42NTQsMy43NDctOS41NDcsOC42NTUtMjIuNzg4LDEwLjk2Yy0xMy4yMzgsMi4zMDYtMjQuN + SwxLjEzNi0yNS4xNTMtMi42MTMgYy0wLjY1My0zLjc0Nyw5LjU1MS04LjY1NCwyMi43OS0xMC45NThDMzYuMDU5LDE0LjkwNyw0Ny4zMTgsMTYuMDc4LDQ3Ljk3LDE5LjgyNnoiLz48cG9seWdvbiBmaWxsPSIjZmFmYWZhIiBwb2ludHM9IjM1LjUxLDI1LjM4OCAzNS40NDIsMjEuNDkyIDM2LjY3MSwyMS40OTIgMzYuNjcxLDI2LjQwMyAzNC45MDUsMjYuNDAzIDMzLjY3OCwyMi4zNzMgMzMuNjUyLDIyLjM3MyAzMy43MiwyNi40MDMgMzIuNDk5LDI2LjQwMyAzMi40OTk + sMjEuNDkyIDM0LjM0MiwyMS40OTIgMzUuNDgzLDI1LjM4OCIvPjxwb2x5Z29uIGZpbGw9IiNmYWZhZmEiIHBvaW50cz0iMTMuMTc3LDIxLjk1MiAxMi40OTcsMjYuNDU1IDExLjE1NywyNi40NTUgMTIuMDc2LDIxLjQ5MiAxNC4yODQsMjEuNDkyIDE1LjIwMSwyNi40NTUgMTMuODY1LDI2LjQ1NSAxMy4yMDQsMjEuOTUyIi8+PHBvbHlnb24gZmlsbD0iI2ZhZmFmYSIgcG9pbnRzPSIxOC45NjQsMjUuMjg2IDE5LjU3NywyMS40OTIgMjEuNjAxLDIxLjQ5MiAyMS43MDgsM + jYuNDU1IDIwLjQ2OCwyNi40NTUgMjAuNDM1LDIxLjk5MyAyMC40MDksMjEuOTkzIDE5LjU4LDI2LjQ1NSAxOC4zMjEsMjYuNDU1IDE3LjQ5LDIxLjk5MyAxNy40NjQsMjEuOTkzIDE3LjQzMywyNi40NTUgMTYuMTksMjYuNDU1IDE2LjMsMjEuNDkyIDE4LjMyNSwyMS40OTIgMTguOTM3LDI1LjI4NiIvPjxwYXRoIGZpbGw9IiNmYWZhZmEiIGQ9Ik05LjA2NywyNS4wNTVjMC4wNDksMC4xMiwwLjAzNCwwLjI3NSwwLjAxMSwwLjM2OGMtMC4wNDIsMC4xNjUtMC4xNTQsMC4 + zMzMtMC40ODMsMC4zMzMgYy0wLjMxMiwwLTAuNS0wLjE3OS0wLjUtMC40NXYtMC40OEg2Ljc2M0w2Ljc2MiwyNS4yMWMwLDEuMTA2LDAuODcxLDEuNDQxLDEuODA1LDEuNDQxYzAuODk4LDAsMS42MzctMC4zMDcsMS43NTQtMS4xMzQgYzAuMDYxLTAuNDI5LDAuMDE1LTAuNzA5LTAuMDA1LTAuODE2Yy0wLjIwOS0xLjAzOS0yLjA5My0xLjM0OS0yLjIzMy0xLjkzYy0wLjAyNC0wLjA5OS0wLjAxNy0wLjIwNS0wLjAwNS0wLjI2MiBjMC4wMzUtMC4xNTgsMC4xNDMtMC4zM + zIsMC40NTMtMC4zMzJjMC4yOSwwLDAuNDYxLDAuMTgsMC40NjEsMC40NWMwLDAuMDkxLDAsMC4zMDcsMCwwLjMwN2gxLjIzN3YtMC4zNDggYzAtMS4wODEtMC45Ny0xLjI1LTEuNjczLTEuMjVjLTAuODgzLDAtMS42MDQsMC4yOTItMS43MzYsMS4wOTljLTAuMDM2LDAuMjIzLTAuMDQxLDAuNDIyLDAuMDExLDAuNjcxIEM3LjA0OSwyNC4xMTgsOC44MTEsMjQuNDEyLDkuMDY3LDI1LjA1NXoiLz48cGF0aCBmaWxsPSIjZmFmYWZhIiBkPSJNMjUuMjA0LDI1LjA0NmMwLjA + 0OSwwLjExOSwwLjAzMywwLjI3LDAuMDExLDAuMzYzYy0wLjA0MSwwLjE2NS0wLjE1MiwwLjMzLTAuNDc5LDAuMzMgYy0wLjMwNywwLTAuNDk0LTAuMTc5LTAuNDk0LTAuNDQ0bC0wLjAwMS0wLjQ3NmgtMS4zMThsLTAuMDAyLDAuMzc5YzAsMS4wOTUsMC44NjMsMS40MjYsMS43ODcsMS40MjYgYzAuODg4LDAsMS42Mi0wLjMwMywxLjczNi0xLjEyMmMwLjA2MS0wLjQyNiwwLjAxOC0wLjcwMi0wLjAwNC0wLjgwN2MtMC4yMDgtMS4wMjktMi4wNzMtMS4zMzYtMi4yMTEtM + S45MTIgYy0wLjAyNC0wLjA5OS0wLjAxNy0wLjIwMy0wLjAwNS0wLjI1N2MwLjAzNi0wLjE2LDAuMTQyLTAuMzI5LDAuNDQ5LTAuMzI5YzAuMjg4LDAsMC40NTUsMC4xNzUsMC40NTUsMC40NDQgYzAsMC4wOSwwLDAuMzA0LDAsMC4zMDRoMS4yMjh2LTAuMzQ1YzAtMS4wNy0wLjk2Mi0xLjIzNy0xLjY1OS0xLjIzN2MtMC44NzMsMC0xLjU4OCwwLjI4OC0xLjcxNywxLjA5IGMtMC4wMzYsMC4yMi0wLjA0LDAuNDE1LDAuMDEyLDAuNjYzQzIzLjIwNiwyNC4xMTgsMjQuOTU + xLDI0LjQxLDI1LjIwNCwyNS4wNDZ6Ii8+PHBhdGggZmlsbD0iI2ZhZmFmYSIgZD0iTTI5LjM3MiwyNS43MTNjMC4zNDQsMCwwLjQ1MS0wLjIzOCwwLjQ3NS0wLjM2YzAuMDEtMC4wNTQsMC4wMTMtMC4xMjUsMC4wMTItMC4xOVYyMS40OWgxLjI1NSB2My41NmMwLjAwMywwLjA5MS0wLjAwNiwwLjI3OS0wLjAxMSwwLjMyNWMtMC4wODgsMC45MjctMC44MjEsMS4yMjctMS43MzIsMS4yMjdjLTAuOTEzLDAtMS42NDYtMC4zMDEtMS43MzMtMS4yMjcgYy0wLjAwNC0wLjA0N + y0wLjAxMy0wLjIzNS0wLjAxMS0wLjMyNXYtMy41NmgxLjI1NHYzLjY3MmMwLDAuMDY0LDAuMDAyLDAuMTM3LDAuMDEyLDAuMTkgQzI4LjkyMSwyNS40NzMsMjkuMDI1LDI1LjcxMywyOS4zNzIsMjUuNzEzeiIvPjxwYXRoIGZpbGw9IiNmYWZhZmEiIGQ9Ik0zOS43MjUsMjUuNjZjMC4zNTksMCwwLjQ4NS0wLjIyNywwLjUwOC0wLjM1OWMwLjAwOS0wLjA1NywwLjAxMi0wLjEyNiwwLjAxMS0wLjE4OXYtMC43MiBoLTAuNTA5di0wLjcyNGgxLjc2VjI1Yy0wLjAwMSwwLjA + 5My0wLjAwMywwLjE2Mi0wLjAxOCwwLjMyN2MtMC4wODIsMC45MDMtMC44NjYsMS4yMjUtMS43NDUsMS4yMjUgYy0wLjg4MSwwLTEuNjYzLTAuMzIyLTEuNzQ3LTEuMjI1Yy0wLjAxNC0wLjE2Ni0wLjAxNi0wLjIzNC0wLjAxOC0wLjMyN2wwLjAwMS0yLjA4OWMwLTAuMDg4LDAuMDExLTAuMjQ0LDAuMDIxLTAuMzI3IGMwLjExLTAuOTI4LDAuODYyLTEuMjI2LDEuNzQzLTEuMjI2YzAuODgsMCwxLjY1MSwwLjI5NywxLjc0MiwxLjIyNmMwLjAxNiwwLjE1OCwwLjAxMSwwL + jMyNywwLjAxMSwwLjMyN3YwLjE2NmgtMS4yNTF2LTAuMjc4IGMwLjAwMSwwLjAwMS0wLjAwMi0wLjExOC0wLjAxNi0wLjE4OWMtMC4wMjEtMC4xMS0wLjExNi0wLjM2Mi0wLjQ5NS0wLjM2MmMtMC4zNjIsMC0wLjQ2NywwLjIzOC0wLjQ5NCwwLjM2MiBjLTAuMDE1LDAuMDY1LTAuMDIxLDAuMTU0LTAuMDIxLDAuMjM0djIuMjdjLTAuMDAxLDAuMDYzLDAuMDAzLDAuMTMyLDAuMDEzLDAuMTg5QzM5LjI0MSwyNS40MzMsMzkuMzY2LDI1LjY2LDM5LjcyNSwyNS42NnoiLz48L3N2Zz4K0 + Brand + Samsung + + + Sony + image/svg+xmlicon-sony.svgPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+Cjxzdmc6c3ZnIHhtbG5zOmlua3NjYXBlPSJodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy9uYW1lc3BhY2VzL2lua3NjYXBlIiB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiIHhtbG5zOnN2Zz0iaH + R0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjgwIDEyODAiIHZlcnNpb249IjEuMSIgaWQ9InN2ZzEiIHNvZGlwb2RpOmRvY25hbWU9Imljb24tc29ueS5zdmciIGlua3NjYXBlOnZlcnNpb249IjEuNC4zICgwZDE1Zjc1MDQyLCAyMDI1LTEyLTI1KSIgd2lkdGg9IjEyODAiIGhlaWdodD0iMTI4MCI+PHNvZGlwb2RpOm5hbWVkdmlldyBpZD0ibmFtZWR2aWV3MSIgcGFnZWNvbG9yPSIjZmZmZmZmIiBib3JkZXJjb2xvcj0iIzAwMDAwMCIgYm9y + ZGVyb3BhY2l0eT0iMC4yNSIgaW5rc2NhcGU6c2hvd3BhZ2VzaGFkb3c9IjIiIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiIGlua3NjYXBlOnBhZ2VjaGVja2VyYm9hcmQ9IjAiIGlua3NjYXBlOmRlc2tjb2xvcj0iI2QxZDFkMSIgaW5rc2NhcGU6em9vbT0iMC42MzQxODYzOSIgaW5rc2NhcGU6Y3g9Ii00NjIuNzk3NjkiIGlua3NjYXBlOmN5PSIyMjUuNDg1NzYiIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMjU2MCIgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iMTM2MC + IgaW5rc2NhcGU6d2luZG93LXg9IjAiIGlua3NjYXBlOndpbmRvdy15PSIwIiBpbmtzY2FwZTp3aW5kb3ctbWF4aW1pemVkPSIxIiBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJnNCIgc2hvd2d1aWRlcz0idHJ1ZSI+PHNvZGlwb2RpOmd1aWRlIHBvc2l0aW9uPSIxNzMuMzcxMDgsNjQxLjg5MDI0IiBvcmllbnRhdGlvbj0iMCwtMSIgaWQ9Imd1aWRlMSIgaW5rc2NhcGU6bG9ja2VkPSJmYWxzZSIvPjwvc29kaXBvZGk6bmFtZWR2aWV3Pjxzdmc6ZGVmcyBpZD0iZGVmczEi + Lz48c3ZnOmcgaWQ9IkxheWVyXzIiPjxzdmc6ZyBpZD0iZzQiIGlua3NjYXBlOmxhYmVsPSJsb2dvIj48c3ZnOnBhdGggZD0ibSA0NTYuMDEyOSw3NTEuNzQ2ODcgYyAtNDYuNDEyNzksMCAtODkuNDIwNzksLTEzLjgyMzk5IC0xMTguMDkyNzksLTM5LjYwMzE5IGEgOTYuODk1OTg5LDk2Ljg5NTk4OSAwIDAgMSAtMzIuMTI3OTksLTczLjE5MDM5IDk4LjMyOTU4OCw5OC4zMjk1ODggMCAwIDEgMzIuMTI3OTksLTcyLjkzNDQgYyAyNi42MjQsLTI0LjE5MTk5IDczLjcyOC + wtMzkuNTUxOTkgMTE4LjA5Mjc5LC0zOS41NTE5OSA0OS4wNzUxOSwwIDg4LjM3MTE5LDEyLjM2NDggMTE4LjM5OTk5LDM5LjYwMzE5IGEgOTcuNDA3OTg5LDk3LjQwNzk4OSAwIDAgMSAzMS42OTI3OSw3Mi44ODMyIDEwMS41Mjk1OSwxMDEuNTI5NTkgMCAwIDEgLTMxLjY5Mjc5LDczLjE5MDM5IGMgLTI3Ljk4MDgsMjUuOTMyOCAtNzEuOTEwNCwzOS42MDMxOSAtMTE4LjM5OTk5LDM5LjYwMzE5IHYgLTI5LjY0NDc5IGMgMjQuNjAxNiwwIDQ3LjQzNjc5LC04LjQ5OTIg + NjMuMzg1NTksLTI0LjM3MTIgMTUuOTQ4OCwtMTUuODcyIDIzLjE5MzYsLTM1LjEyMzIgMjMuMTkzNiwtNTguODc5OTkgMCwtMjIuNjgxNiAtNy45NjE2LC00My44Nzg0IC0yMy4xOTM2LC01OC44OCAtMTUuNzQ0LC0xNS40ODc5OSAtMzkuMTE2NzksLTI0LjIxNzU5IC02My4zODU1OSwtMjQuMjE3NTkgLTI0LjI2ODgsMCAtNDcuNzQzOTksOC42NTI4IC02My40ODc5OSwyNC4yMTc1OSAtMTUuMTgwOCwxNS4wMjcyIC0yMy4wNCwzNi4zMDA4IC0yMy4wNCw1OC44OCBhID + gyLjM1NTE5LDgyLjM1NTE5IDAgMCAwIDIzLjA0LDU4Ljg3OTk5IGMgMTUuNzQ0LDE1LjY5MjggMzkuMDY1NTksMjQuMzcxMiA2My40ODc5OSwyNC4zNzEyIHogTSAxMTcuMTIwMTQsNTI2LjQ2NjkgYyAtMjQuODA2MzkyLDAgLTUyLjk5MTk4OSw0LjY1OTIgLTc2Ljc5OTk4NiwxNS4zNiBDIDE4LjA5OTM1NSw1NTEuNzU5NyAxLjU3NWUtNCw1NjcuNzA4NDkgMS41NzVlLTQsNTk0LjE1MzI5IGEgNTQuMjIwNzk0LDU0LjIyMDc5NCAwIDAgMCAxNC43MTk5OTg1LDM3LjI3 + MzYgYyA2LjQyNTU5OSw1LjkzOTIgMTYuNzkzNTk5LDE2LjAyNTYgNDMuODc4Mzk2LDIxLjk2NDggMTIuMTA4Nzk4LDIuNTU5OTkgMzcuOTkwMzk1LDYuNjgxNTkgNjMuNzY5NTg4LDkuMzk1MTkgMjUuNzc5MiwyLjcxMzYgNTAuNzY0OCw1LjEyIDYxLjAwNDgsNy44NTkyIDguMTQwOCwyLjA3MzYgMjEuODM2NzksNC44ODk2IDIxLjgzNjc5LDIwLjI0OTYgMCwxNS4zNiAtMTQuNDEyNzksMTkuOTY4IC0xNi45MjE1OSwyMC45NjY0IC0yLjUwODgsMC45OTg0IC0xOS44MT + Q0LDguOTM0NCAtNTAuODkyOCw4LjkzNDQgYSAyMTYuNDIyMzcsMjE2LjQyMjM3IDAgMCAxIC02MC41OTUxOSwtMTAuNDE5MiBjIC0xMS41OTY3OTksLTQuMTQ3MiAtMjMuNzU2Nzk3LC05LjYgLTM1LjA5NzU5NiwtMjMuNDQ5NiBhIDQwLjI2ODc5NSw0MC4yNjg3OTUgMCAwIDEgLTcuMjk1OTk5LC0yMi4yMjA4IEggNi4yNDY1NTY3IHYgNzguODQ3OTkgSCAzNy41Mjk3NTQgdiAtMTAuNjc1MTkgYSA0LjQ1NDM5OTUsNC40NTQzOTk1IDAgMCAxIDYuNzU4NCwtMy44NCAy + NDYuNDI1NTcsMjQ2LjQyNTU3IDAgMCAwIDQ1Ljc3Mjc5NCwxNC43OTY3OSBjIDE2LjQzNTIwMiwzLjQzMDQgMjcuMDU5MTkyLDUuOTEzNiA0Ny40ODc5OTIsNS45MTM2IGEgMjAyLjYyMzk4LDIwMi42MjM5OCAwIDAgMCA2My42NDE2LC04Ljk4NTYgMTExLjA3ODM5LDExMS4wNzgzOSAwIDAgMCAzNy44MTExOSwtMTguNjYyMzkgNTEuODE0Mzk0LDUxLjgxNDM5NCAwIDAgMCAyMC4yNDk1OSwtNDEuNDk3NiA1OC4wNjA3OTMsNTguMDYwNzkzIDAgMCAwIC0xNi4zNTgzOS + wtNDAuODA2MzkgNzIuMDEyNzkyLDcyLjAxMjc5MiAwIDAgMCAtMjAuMTcyOCwtMTMuNzk4NCAxNDguNjA3OTgsMTQ4LjYwNzk4IDAgMCAwIC0yNC44ODMxOSwtOC42Nzg0IGMgLTE2LjIzMDQsLTMuOTY4IC01Mi42ODQ4LC04LjkzNDQgLTcwLjExODQsLTEwLjY3NTIgLTE4LjI3ODM5LC0xLjg5NDQgLTQ5Ljk5Njc5LC00LjUzMTIgLTYyLjY2ODc4OSwtOC40NDggLTMuODM5OTk5LC0xLjIwMzIgLTExLjY3MzU5OSwtNC45MTUyIC0xMS42NzM1OTksLTE0LjAwMzIgMCwt + Ni40NzY4IDMuNTg0LC0xMS45NTUyIDEwLjY0OTU5OSwtMTYuMzg0IEMgNzUuMjY0MTUsNTYwLjc3MDkgOTcuOTQ1NzQ3LDU1Ni4zOTMzIDEyMS42MDAxNCw1NTYuMzkzMyBhIDE2Ni45ODg3OCwxNjYuOTg4NzggMCAwIDEgNjYuNzEzNiwxMy4wMzAzOSA3Mi44NTc1OTEsNzIuODU3NTkxIDAgMCAxIDE1Ljg3MTk5LDkuNDcyIDQ3LjcxODM5NCw0Ny43MTgzOTQgMCAwIDEgMTUuNjQxNiwyNi4xNjMyIGggMjUuMjY3MiBWIDUzNi40MjUzIGggLTI4LjE2IHYgNy45NjE2IG + MgMCwyLjU2IC0yLjU2LDUuOTM5MiAtNy42OCwzLjE0ODggLTEyLjY5NzU5LC02LjYwNDggLTQ4LjM4Mzk5LC0yMC44ODk2IC05Mi4xMzQzOSwtMjEuMDY4OCB6IG0gNjE4LjIxNDMzLDEyLjU5NTIgMTM3LjYyNTU4LDEyNC4xODU1OCAtMS40MDgsLTgzLjYwOTU5IGMgLTAuMTUzNiwtMTAuOTgyNCAtMi4xNTA0LC0xNS41NjQ3OSAtMTQuMDI4OCwtMTUuNTY0NzkgaCAtMjUuODU1OTkgdiAtMjUuMDExMiBoIDExNy43NTk5OCB2IDI1LjAxMTIgaCAtMjUuMjY3MTkgYyAt + MTIuMDgzMiwwIC0xMi44LDMuODkxMTkgLTEzLjAwNDgsMTUuNTY0NzkgbCAyLjEyNDgsMTU5Ljc2OTU5IGggLTQwLjMyIEwgNzE0LjQxOTI3LDU5Ny45NDIwOSB2IDEwMC4zNzc1OSBjIDAuMTI4LDEwLjkzMTIgMC42NCwxNi4wNzY4IDExLjg3ODQsMTYuMDc2OCBoIDI4LjE2IHYgMjUuMDExMiBIIDYzOS4wMjcyOCB2IC0yNS4wMTEyIGggMjcuMDMzNiBjIDEwLjA4NjM5LDAgOS42NzY3OSwtOS42MjU2IDkuNjc2NzksLTE2LjY0IFYgNTgwLjU4NTI5IGMgMCwtNy42OC + AtMS4wNzUyLC0xNi40ODYzOSAtMTYuODk1OTksLTE2LjQ4NjM5IGggLTIxLjkxMzYgViA1MzkuMDYyMSBaIE0gMTA4My43NzYsNzE0LjM0NTI4IGEgNTUuODU5MTkzLDU1Ljg1OTE5MyAwIDAgMCA2Ljk2MzIsLTAuNDM1MiA4LjYyNzE5OSw4LjYyNzE5OSAwIDAgMCA1LjQyNzIsLTQuODEyOCAyOC4wMDYzOTcsMjguMDA2Mzk3IDAgMCAwIDAuNTM3NiwtNS40MDE2IHYgLTM5LjU1MiBjIDAsLTEuMzMxMiAwLC0xLjM1NjggLTEuNjg5NiwtMy40NTYgLTEuNjg5NiwtMi4w + OTkyIC03Mi4wODk2LC04MS45MTk5OSAtNzUuMjg5NiwtODUuNTAzOTkgLTMuOTkzNiwtNC4zNTIgLTExLjAwOCwtMTEuMDg0NzkgLTIxLjY4MzIsLTExLjA4NDc5IGggLTI0LjQ0Nzk2IHYgLTI1LjAzNjggaCAxMzcuOTgzOTYgdiAyNC45ODU2IGggLTE2LjY0IGMgLTMuODQsMCAtNi40LDMuNjYwNzkgLTMuMTIzMiw3LjY3OTk5IDAsMCA0Ni40Mzg0LDU1LjU1MiA0Ni44NzM2LDU2LjE0MDggMC40MzUyLDAuNTg4OCAwLjgxOTIsMC43MTY4IDEuNDA4LDAuMTc5MiAwLj + U4ODgsLTAuNTM3NiA0Ny41OTA0LC01NS44MDggNDcuOTQ4OCwtNTYuMzIgYSA0Ljc4NzE5OTQsNC43ODcxOTk0IDAgMCAwIC00LjA5NiwtNy42Nzk5OSBoIC0xNy4wNzUyIFYgNTM5LjA2MjEgSCAxMjgwIHYgMjUuMDM2OCBoIC0yNS4yNjcyIGMgLTkuMTY0OCwwIC0xMi44LDEuNjg5NTkgLTE5Ljc4ODgsOS40NzE5OSBsIC03Ni4xNiw4Ni44ODYzOSBhIDUuMzc1OTk5NCw1LjM3NTk5OTQgMCAwIDAgLTAuOTIxNiwzLjY4NjQgdiAzOS41MjY0IGEgMjguMTU5OTk3LDI4 + LjE1OTk5NyAwIDAgMCAwLjU2MzIsNS40MDE2IDguNTI0Nzk5LDguNTI0Nzk5IDAgMCAwIDUuNDAxNiw0LjgxMjggNTAuNjExMTk0LDUwLjYxMTE5NCAwIDAgMCA2LjkxMiwwLjQzNTIgaCAyNS44MzA0IHYgMjUuMDM2OCBoIC0xMzcuMjY3MiB2IC0yNS4wMzY4IHoiIGlkPSJwYXRoMSIgZmlsbD0iIzAwMDAwMCIgc3R5bGU9InN0cm9rZS13aWR0aDoyLjU2Ii8+PC9zdmc6Zz48L3N2ZzpnPjwvc3ZnOnN2Zz4K0 + Brand + Sony + + + Toshiba + image/svg+xmllogo-toshiba.svgPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+Cjxzdmc6c3ZnIHhtbG5zOmlua3NjYXBlPSJodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy9uYW1lc3BhY2VzL2lua3NjYXBlIiB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiIHhtbG5zOnN2Zz0 + iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIHdpZHRoPSI4MDAiIGhlaWdodD0iODAwIiB2ZXJzaW9uPSIxLjAiIHZpZXdCb3g9IjAgMCA4MDAgODAwLjAxOTY5IiBpZD0ic3ZnMSIgc29kaXBvZGk6ZG9jbmFtZT0ibG9nby10b3NoaWJhLnN2ZyIgaW5rc2NhcGU6dmVyc2lvbj0iMS40LjMgKDBkMTVmNzUwNDIsIDIwMjUtMTItMjUpIj48c3ZnOmRlZnMgaWQ9ImRlZnMxIi8+PHNvZGlwb2RpOm5hbWVkdmlldyBpZD0ibmFtZWR2a + WV3MSIgcGFnZWNvbG9yPSIjZmZmZmZmIiBib3JkZXJjb2xvcj0iIzAwMDAwMCIgYm9yZGVyb3BhY2l0eT0iMC4yNSIgaW5rc2NhcGU6c2hvd3BhZ2VzaGFkb3c9IjIiIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiIGlua3NjYXBlOnBhZ2VjaGVja2VyYm9hcmQ9IjAiIGlua3NjYXBlOmRlc2tjb2xvcj0iI2QxZDFkMSIgc2hvd2d1aWRlcz0idHJ1ZSIgaW5rc2NhcGU6em9vbT0iMS41MzgxMjUiIGlua3NjYXBlOmN4PSIzNzguNzA3ODQiIGlua3NjYXBlOmN5PSIyODg + uMDEzIiBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjI1NjAiIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjEzNjAiIGlua3NjYXBlOndpbmRvdy14PSIwIiBpbmtzY2FwZTp3aW5kb3cteT0iMCIgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSIgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ic3ZnMSI+PHNvZGlwb2RpOmd1aWRlIHBvc2l0aW9uPSIyMjcuMzE3MTYsMzk5LjM4NTQyIiBvcmllbnRhdGlvbj0iMCwtMSIgaWQ9Imd1aWRlMSIgaW5rc2NhcGU6bG9ja2VkPSJmY + WxzZSIvPjwvc29kaXBvZGk6bmFtZWR2aWV3PgogIDxzdmc6cGF0aCBmaWxsPSIjZTYxZTFlIiBkPSJtIDc2Ni4xMDAxNiw0NTkuNzEzNiBoIDM0LjU1IGwgLTM1LjY1LC0xMTcuNjYgLTQ5LjEsLTAuMDAyIC0zNS42NSwxMTcuNjYgaCAzNC41NiBsIDYuMywtMjEuNzggaCAzOC42NiBsIDYuMzMsMjEuNzggbSAtMzcuNTEsLTQ3Ljk0MyAxMS43NiwtNDAuNjUxIGggMC4yIGwgMTEuNzYsNDAuNjUxIHogbSAtNTU1LjQ2LDUwLjA1NSBjIDM1LjQ4LDAgNTIuNjMsLTYuMjU + gNTUuMDYsLTM4LjI2NSAwLjU4LC03LjYxOCAwLjY5LC0xNS40MzkgMC42OSwtMjIuNjg5IDAuMDEsLTcuMjI1IC0wLjExLC0xNS4wNTQgLTAuNjksLTIyLjY3MSAtMi40MywtMzIuMDI1IC0xOS41OCwtMzguMjY1IC01NS4wNiwtMzguMjY1IC0zNS40OCwwIC01Mi42Miw2LjI0IC01NS4wNCwzOC4yNjUgLTAuNTksNy42MTcgLTAuNzEsMTUuNDQ2IC0wLjcxLDIyLjY3MSAwLjAxLDcuMjUgMC4xMiwxNS4wNzEgMC43MSwyMi42ODkgMi40MiwzMi4wMTUgMTkuNTYsMzguMjY1IDU1LjA0LDM4LjI2NSBtIC0yMi4zMSwtNjAuOTU0IGMgMCwtNi40NjEgMC4xNiwtMTAuMjggMC4zLC0xMy4xMTQgMC45LC0xOC4xNjEgOC4wNywtMjAuMjc4IDIyLjAxLC0yMC4yNzggMTMuOTUsMCAyMS4xMiwyLjExNyAyMi4wMSwyMC4yNzggMC4xNCwyLjgzMyAwLjMxLDYuNjUyIDAuMzEsMTMuMTE0IDAsNi40ODIgLTAuMTcsMTAuMzA4IC0wLjMxLDEzLjEzNSAtMC44OSwxOC4xNjQgLTguMDYsMjAuMjg1IC0yMi4wMSwyMC4yODUgLTEzLjk0LDAgLTIxLjExLC0yLjEyMSAtMjIuMDEsLTIwLjI4NSAtMC4xNCwtMi44MjcgLTAuMywtNi42NTMgLTAuMywtMTMuMTM1IHogTSAwLjY1MDE1ODIyLDM0Mi4xMDU2IHYgMjkuMzMxIEggMzUuODIyMTU4IHYgODguMzI3IGggMzUuMTg1IHYgLTg4LjMyNyBoIDM1LjE3MzAwMiB2IC0yOS4zMzEgSCAwLjY1MDE1ODIyIE0gNTQwLjUwMDE2LDQ1OS43MTM2IHYgLTExNy42NjIgaCAtMzMuMzkgdiAxMTcuNjYyIGggMzMuMzkgbSAtMTM0LjM1LC03NC43MDMgdiAtNDIuOTU5IGggLTMzLjIgdiAxMTcuNjYyIGggMzMuMiB2IC00NS4zNzIgaCAzOC41OCB2IDQ1LjM3MiBoIDMzLjE5IHYgLTExNy42NjIgaCAtMzMuMTkgdiA0Mi45NTkgaCAtMzguNTggbSAyNDQuMTcsMTMuMjA2IGMgMTQuNzksLTMuNzgxIDE5LjEzLC0xMi42MTYgMTkuMTMsLTI1LjM4NiAwLC0yNS44NTkgLTE2LjI3LC0zMC43OCAtMzkuNCwtMzAuNzggaCAtNTkuOTUgdiAxMTcuNjYgaCA2Mi45MiBjIDI4Ljk3LDAgMzguNzEsLTEyLjQ4IDM4LjcxLC0zMS42NzUgMCwtMTMuMzgzIC0zLjA2LC0yNS4xOTEgLTIxLjQxLC0yOS44MjIgbSAtNDcuMDMsMTMuMTY5IGggMjMuMDIgYyA5LjMsMCAxMS4yNCw0LjA3NCAxMS4yNCwxMC43IDAsNi42MzIgLTMuNjQsMTAuNzE3IC0xMS4yNCwxMC43MTcgaCAtMjMuMDIgeiBtIDAsLTQyLjQyNSBoIDIzLjAyIGMgNi4wMSwwIDkuNzMsMi44NTEgOS43Myw5LjcwOCAwLDUuODc4IC0zLjY4LDkuNDk2IC05LjczLDkuNDk2IGggLTIzLjAyIHogbSAtMzU1LjA2LDUyLjE0MyBoIDMxLjY1IGMgMC4wMyw1LjcwOCAwLjc2LDkuNTIzIDMuNTMsMTEuNjMgMy4xNSwyLjM3NCA1Ljk3LDMuMTU4IDE1LjMyLDMuMTU4IDksMCAxOC44NiwwIDE4Ljg2LC0xMS4wODUgMCwtOC43NDIgLTUuNTEsLTEwLjczNyAtMTUuNjgsLTExLjI3OSAtMjUuMjIsLTEuMzM2IC0zNC4zNCwtMi4wNDkgLTQzLjczLC05LjAyNSAtNi40LC00Ljc1NyAtOS43MiwtMTQuMDE4IC05LjcyLC0yNi41NDIgMCwtMjEuMjk3IDcuNDMsLTI4Ljc2OCAxOC4xNSwtMzMuOTgxIDExLjA2LC01LjM4MSA1NC40NywtNS4zODEgNjYuMTUsMCAxNC42OSw2Ljc2OCAxNS4xMiwyMS40MiAxNS4xMiwzNS4wMTEgaCAtMzEuNTcgYyAtMC4wNiwtNi45MjkgLTEuNjIsLTguODg2IC0yLjg5LC0xMC4xNzUgLTMuMjgsLTIuOTA4IC03Ljk1LC0zLjUyMiAtMTQuNjksLTMuNTIyIC04LjE2LDAgLTE3LjYsMC4zNjggLTE3LjYsMTAuMjc3IDAsNy41NiAzLjI3LDEwLjcyIDExLjg1LDExLjI3NiAxMS43OSwwLjc1NCAzNS4wMiwxLjQ5NyA0My4zLDYuMzgzIDExLjYxLDYuODY3IDE0LjYyLDE2LjE1OSAxNC42MiwzMS4zMTkgMCwyMS45MDggLTcuODQsMjguMzM4IC0xOC43NSwzMy4xNTggLTEyLjU5LDUuNTYgLTU0LjY0LDUuNTYgLTY4LjMxLC0wLjQzIC0xNS4zLC02LjY3IC0xNS42MSwtMTkuOTY0IC0xNS42MSwtMzYuMTczIiBpZD0icGF0aDEiLz4KPC9zdmc6c3ZnPgo=0 + Brand + Toshiba + + diff --git a/datamodels/2.x/itop-config-mgmt/data/en_us.data.itop-osfamily.xml b/datamodels/2.x/itop-config-mgmt/data/en_us.data.itop-osfamily.xml index f06fb02ab..371582bad 100755 --- a/datamodels/2.x/itop-config-mgmt/data/en_us.data.itop-osfamily.xml +++ b/datamodels/2.x/itop-config-mgmt/data/en_us.data.itop-osfamily.xml @@ -1,48 +1,116 @@ + - - Arch - OS Family - Arch - - - Debian - OS Family - Debian - - - Oracle Linux - OS Family - Oracle Linux - - - Red Hat - OS Family - Red Hat - - - Ubuntu - OS Family - Ubuntu - - - Ubuntu server - OS Family - Ubuntu server - - - vCenter Server - OS Family - vCenter Server - - - Windows - OS Family - Windows - - - Windows server - OS Family - Windows server - + + Arch + image/svg+xmlicons8-arch-linux.svgPD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmlld0JveD0iMCwwLDI1NiwyNTYiIHdpZHRoPSI0OHB4IiBoZWlnaHQ9IjQ4cHgiIGZpbGwtcnVsZT0ibm9uemVybyI+PGcgZmlsbD0iIzAwODhjYyIgZmlsbC1ydWxlPSJub256ZXJvIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgZm9udC1mYW1pbHk9Im5vbmUiIGZvbnQtd2VpZ2h0PSJub25lIiBmb250LXNpemU9Im5vbmUiIHRleHQtYW5jaG9yPSJub25lIiBzdHlsZT0ibWl4LWJsZW5kLW1vZGU6IG5vcm1hbCI+PGcgdHJhbnNmb3JtPSJzY2FsZSg1LjMzMzMzLDUuMzMzMzMpIj48cGF0aCBkPSJNMjguNDY1LDM4LjYxMWMwLjQxOSwtMS4xMDUgMC42NjQsLTIuMzY1IDAuNjY0LC0zLjcxNGMwLC00LjEzMyAtMi4yMTEsLTcuNDk0IC00LjkyOSwtNy40OTRjLTIuNzQxLDAgLTQuOTUxLDMuMzYxIC00Ljk1MSw3LjQ5NGMwLDEuMzI2IDAuMjIxLDIuNTg2IDAuNjQxLDMuNjY5Yy05LjA0MSwwLjk1MSAtMTUuNDA3LDQuNzMxIC0xNy45OTMsNi40MzJjNC4zNTUsLTYuMjc4IDguOTA5LC0xMy42MzggMTMuMjYyLC0yMi4xMDVjMS4wODMsLTIuMTAxIDIuMTAxLC00LjE3OCAzLjA1LC02LjIxMWMwLjM3NSwwLjI0MyAwLjc1MSwwLjUwOSAxLjE3MSwwLjc3NWMxLjk0NSwxLjIxNSAzLjc1OSwxLjg3OSA1LjA4NCwyLjIzM2MtMC45NzMsLTAuNzMgLTIuMDMzLC0xLjYxMyAtMy4xMTYsLTIuNjk3Yy0wLjgxNywtMC44MTcgLTEuNTQ3LC0xLjYzNyAtMi4xNjcsLTIuNDMzYzEuODM1LC00LjAyMiAzLjQyNywtNy44OTEgNC44MTksLTExLjU2YzIuMzIsNi4xNDQgNS4yMTcsMTIuODQyIDguODQxLDE5Ljg5M2MyLjM0Myw0LjUzMSA0LjczMSw4Ljc1NCA3LjExNywxMi42NDRjLTAuNjg1LC0wLjM3NSAtMS40MzcsLTAuNzMgLTIuMjMzLC0xLjAzOWMtMS4zNzEsLTAuNTMgLTIuNjUyLC0wLjg2MiAtMy43NTksLTEuMDZjMS41MDMsMC43NTEgMy4yNSwxLjc0NyA1LjA4NCwzLjA3M2MxLjE5NCwwLjg4NSAyLjI1NCwxLjc2OSAzLjE2MSwyLjYzMWMwLjAyMSwwLjAyMSAwLjAyMSwwLjAyMSAwLjA0NSwwLjA0NWMxLjI2LDIuMDU2IDIuNTY1LDMuOTU3IDMuODQ2LDUuODEzYy0yLjU0MSwtMS42ODEgLTguNzk2LC01LjM5NSAtMTcuNjM3LC02LjM4OXoiLz48L2c+PC9nPjwvc3ZnPgo=0 + OS Family + Arch + + + Debian + image/svg+xmlicons8-debian.svgPD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNDggNDgiIHdpZHRoPSI0OHB4IiBoZWlnaHQ9IjQ4cHgiPjxwYXRoIGZpbGw9IiNFOTFFNjMiIGQ9Ik0yNi43NjMsMjQuNTQ4Yy0wLjYxNCwwLjAxLDAuMTE3LDAuMzE3LDAuOTE4LDAuNDRjMC4yMi0wLjE3MiwwLjQxOS0wLj + M0OCwwLjYtMC41MTVDMjcuNzgxLDI0LjU5MiwyNy4yNzQsMjQuNTk0LDI2Ljc2MywyNC41NDggTTMwLjA1NCwyMy43MjdjMC4zNjQtMC41LDAuNjMxLTEuMDU1LDAuNzIzLTEuNjI0Yy0wLjA4MiwwLjQwNS0wLjMwMywwLjc1NS0wLjUxLDEuMTI4Yy0xLjE0NiwwLjcyMS0wLjEwOC0wLjQzLDAtMC44NjVDMjkuMDM1LDIzLjkxMywzMC4wOTgsMjMuMjkzLDMwLjA1NCwyMy43MjcgTTMxLjI2OSwyMC41NjhjMC4wNzMtMS4xMDUtMC4yMTktMC43NTYtMC4zMTctMC4zMzZD + MzEuMDY4LDIwLjI5NCwzMS4xNTYsMjEuMDEzLDMxLjI2OSwyMC41NjggTTI0LjQzOSw1LjQ3OGMwLjMyNywwLjA1OCwwLjcwNiwwLjEwNCwwLjY1MywwLjE4M0MyNS40NDksNS41ODIsMjUuNTMxLDUuNTEsMjQuNDM5LDUuNDc4IE0yNS4wOTMsNS42NmwtMC4yMzIsMC4wNDdsMC4yMTUtMC4wMTdMMjUuMDkzLDUuNjYgTTM1LjI5NCwyMC45ODZjMC4wMzgsMC45OTEtMC4yOSwxLjQ3Mi0wLjU4NSwyLjMyMmwtMC41MjksMC4yNjZjLTAuNDM1LDAuODQxLDAuMDQxLDAuNT + M1LTAuMjY4LDEuMjAyYy0wLjY3OSwwLjYwMy0yLjA1NSwxLjg4My0yLjQ5NiwyLjAwNGMtMC4zMjEtMC4wMDksMC4yMTgtMC4zODIsMC4yODktMC41MjZjLTAuOTA2LDAuNjItMC43MjgsMC45MzQtMi4xMTMsMS4zMTNsLTAuMDQxLTAuMDljLTMuNDE5LDEuNjA3LTguMTY2LTEuNTc2LTguMTAzLTUuOTI4Yy0wLjAzNywwLjI3NS0wLjEwNCwwLjIwOS0wLjE4LDAuMzJjLTAuMTc1LTIuMjM3LDEuMDMzLTQuNDg2LDMuMDczLTUuNDAzYzEuOTk1LTAuOTg3LDQuMzM1LTAu + NTgsNS43NjMsMC43NWMtMC43ODUtMS4wMjgtMi4zNDgtMi4xMTktNC4xOTktMi4wMTdjLTEuODE0LDAuMDI5LTMuNTEsMS4xODItNC4wNzcsMi40MzRjLTAuOTI5LDAuNTg1LTEuMDM4LDIuMjU2LTEuNDQxLDIuNTYzYy0wLjU0NSw0LjAwMywxLjAyNCw1LjczMywzLjY4LDcuNzY4YzAuNDE3LDAuMjgyLDAuMTE4LDAuMzI2LDAuMTc1LDAuNTQxYy0wLjg4My0wLjQxMi0xLjY5LTEuMDM3LTIuMzU0LTEuODAxYzAuMzUzLDAuNTE3LDAuNzMzLDEuMDE3LDEuMjIzLDEuND + FjLTAuODMxLTAuMjc5LTEuOTQyLTIuMDEzLTIuMjY3LTIuMDg0YzEuNDM1LDIuNTY3LDUuODE4LDQuNTAyLDguMTEzLDMuNTQxYy0xLjA2MiwwLjA0LTIuNDEyLDAuMDIxLTMuNjA0LTAuNDJjLTAuNTAxLTAuMjU3LTEuMTgzLTAuNzkxLTEuMDYyLTAuODkzYzMuMTMzLDEuMTcxLDYuMzY5LDAuODg3LDkuMDc4LTEuMjg2YzAuNjg5LTAuNTM3LDEuNDQzLTEuNDQ5LDEuNjYyLTEuNDY0Yy0wLjMyNywwLjQ5MywwLjA1NywwLjIzOS0wLjE5NywwLjY3NGMwLjY4OC0xLjEw + OS0wLjI5OS0wLjQ0OSwwLjcxMS0xLjkxM2wwLjM3MywwLjUxMmMtMC4xMzktMC45MTcsMS4xNDMtMi4wMzMsMS4wMTItMy40ODljMC4yOTEtMC40NDUsMC4zMjYsMC40NzgsMC4wMTUsMS41MDJjMC40MzQtMS4xMzYsMC4xMTMtMS4zMTcsMC4yMjQtMi4yNTRjMC4xMjEsMC4zMTUsMC4yNzksMC42NDgsMC4zNTksMC45ODFjLTAuMjgxLTEuMDk3LDAuMjg5LTEuODQ4LDAuNDMzLTIuNDg1Yy0wLjE0Mi0wLjA2My0wLjQzNSwwLjQ4NS0wLjUwMy0wLjgxMmMwLjAxLTAuNT + YyLDAuMTU2LTAuMjk1LDAuMjE0LTAuNDM1Yy0wLjExMS0wLjA2NC0wLjQtMC40OTYtMC41NzctMS4zMjNjMC4xMjctMC4xOTMsMC4zNDIsMC41MDYsMC41MTYsMC41MzNjLTAuMTEyLTAuNjU1LTAuMzA0LTEuMTU5LTAuMzEzLTEuNjY1Yy0wLjUxLTEuMDYxLTAuMTgxLDAuMTQzLTAuNTkyLTAuNDU4Yy0wLjU0My0xLjY4NywwLjQ0OS0wLjM5LDAuNTE0LTEuMTU2YzAuODIsMS4xODgsMS4yODksMy4wMjksMS41MDQsMy43OTJjLTAuMTY0LTAuOTMtMC40MjgtMS44MzIt + MC43NTItMi43MDRjMC4yNDksMC4xMDgtMC40MDEtMS45MTEsMC4zMjQtMC41NzVjLTAuNzcyLTIuODQ4LTMuMzE0LTUuNTExLTUuNjUtNi43NmMwLjI4NiwwLjI2MiwwLjY0NiwwLjU5MSwwLjUxNywwLjY0MmMtMS4xNjMtMC42OS0wLjk1OS0wLjc0NS0xLjEyNC0xLjA0MWMtMC45NDYtMC4zODMtMS4wMSwwLjAzNC0xLjYzNiwwYy0xLjc4Ni0wLjk0My0yLjEyOS0wLjg0NS0zLjc3Mi0xLjQzN2wwLjA3OCwwLjM0OWMtMS4xODQtMC4zOTQtMS4zNzksMC4xNDYtMi42NT + csMC4wMDJjLTAuMDc4LTAuMDYyLDAuNDEtMC4yMTksMC44MTEtMC4yNzhjLTEuMTQzLDAuMTUtMS4wOS0wLjIyOC0yLjIwOCwwLjA0MmMwLjI3Ny0wLjE5NywwLjU2Ni0wLjMyMiwwLjg2MS0wLjQ4NmMtMC45MzIsMC4wNTktMi4yMjYsMC41NDItMS44MjUsMC4xMDNjLTEuNTIxLDAuNjc2LTQuMjIsMS42My01LjczNSwzLjA1MWwtMC4wNDctMC4zMjJjLTAuNjk0LDAuODM1LTMuMDI4LDIuNDkyLTMuMjE1LDMuNTdsLTAuMTg1LDAuMDQzYy0wLjM2MSwwLjYxMy0wLjU5 + NSwxLjMwNS0wLjg4MSwxLjkzNWMtMC40NzQsMC44MDYtMC42OTIsMC4zMTEtMC42MjYsMC40MzZjLTAuOTI5LDEuODgzLTEuMzksMy40NjctMS43OSw0Ljc2OGMwLjI4NCwwLjQyNCwwLjAwNywyLjU1OCwwLjExMyw0LjI2NGMtMC40NjcsOC40MjksNS45MTYsMTYuNjA5LDEyLjg5MSwxOC41YzEuMDIzLDAuMzY1LDIuNTQyLDAuMzU0LDMuODM2LDAuMzljLTEuNTI1LTAuNDM4LTEuNzIyLTAuMjMyLTMuMjA5LTAuNzQ5Yy0xLjA3NC0wLjUwNi0xLjMwOC0xLjA4Mi0yLj + A2Ni0xLjc0bDAuMywwLjUzYy0xLjQ5LTAuNTI2LTAuODY3LTAuNjUyLTIuMDc4LTEuMDM0bDAuMzIxLTAuNDI0Yy0wLjQ4Mi0wLjAzMi0xLjI3OS0wLjgxMS0xLjQ5Ny0xLjI0MWwtMC41MjgsMC4wMjFjLTAuNjM0LTAuNzgzLTAuOTcyLTEuMzQ4LTAuOTQ4LTEuNzg1bC0wLjE3LDAuMzA1Yy0wLjE5NC0wLjMzMi0yLjMzNS0yLjkzNy0xLjIyNC0yLjMzYy0wLjIwNy0wLjE4OC0wLjQ4MS0wLjMwNy0wLjc3OS0wLjg1bDAuMjI3LTAuMjU4Yy0wLjUzNS0wLjY4Ni0wLjk4 + My0xLjU2OC0wLjk0OS0xLjg2YzAuMjg0LDAuMzg0LDAuNDgyLDAuNDU0LDAuNjc5LDAuNTIyYy0xLjM1MS0zLjM0OS0xLjQyNi0wLjE4Ny0yLjQ0OC0zLjQwOWwwLjIxNi0wLjAxOWMtMC4xNjYtMC4yNDYtMC4yNjUtMC41MjEtMC4zOTktMC43ODVsMC4wOTQtMC45MzhjLTAuOTcyLTEuMTI1LTAuMjcyLTQuNzgxLTAuMTMyLTYuNzgzYzAuMDk3LTAuODE2LDAuODExLTEuNjg0LDEuMzU0LTMuMDQ1bC0wLjMzMi0wLjA1NWMwLjYzMi0xLjEwNCwzLjYxMi00LjQzMyw0Lj + k5LTQuMjZjMC42NjktMC44NDEtMC4xMzItMC4wMDItMC4yNjMtMC4yMTVjMS40NjktMS41MiwxLjkzLTEuMDczLDIuOTItMS4zNDljMS4wNjgtMC42MzMtMC45MTcsMC4yNTEtMC40MS0wLjIzOWMxLjg0OC0wLjQ3MywxLjMxLTEuMDczLDMuNzE4LTEuMzExYzAuMjU0LDAuMTQ1LTAuNTksMC4yMjMtMC44LDAuNDFjMS41MzgtMC43NTMsNC44Ny0wLjU4NCw3LjAzNCwwLjQxN2MyLjUxMSwxLjE3Myw1LjMzLDQuNjQyLDUuNDQzLDcuOTA0bDAuMTI2LDAuMDM1Yy0wLjA2 + MywxLjI5OCwwLjE5OCwyLjc5OC0wLjI1Nyw0LjE3NUwzNS4yOTQsMjAuOTg2IE0yMC4wNzIsMjUuMzg5bC0wLjA4NiwwLjQzMWMwLjQwMywwLjU0NywwLjcyNCwxLjE0MiwxLjIzNywxLjU2N0MyMC44NTMsMjYuNjY0LDIwLjU3NywyNi4zNjQsMjAuMDcyLDI1LjM4OSBNMjEuMDIzLDI1LjM1M2MtMC4yMTMtMC4yMzctMC4zNC0wLjUxOC0wLjQ4LTAuODAyYzAuMTM1LDAuNDk1LDAuNDExLDAuOTIyLDAuNjY5LDEuMzU3TDIxLjAyMywyNS4zNTMgTTM3Ljg3NywyMS42OD + hsLTAuMDg4LDAuMjI2Yy0wLjE2NiwxLjE3NC0wLjUyMywyLjMzMi0xLjA2OCwzLjQxMkMzNy4zMjQsMjQuMTg5LDM3LjcxNCwyMi45NDcsMzcuODc3LDIxLjY4OCBNMjQuNTYsNS4xODVDMjQuOTc0LDUuMDMxLDI1LjU3OSw1LjEwMSwyNi4wMTksNWMtMC41NzMsMC4wNDgtMS4xNDQsMC4wNzktMS43MDYsMC4xNTFMMjQuNTYsNS4xODUgTTEwLjAwNywxMi45MjNjMC4wOTUsMC44ODItMC42NjcsMS4yMjksMC4xNjcsMC42NDRDMTAuNjIzLDEyLjU2MiwxMCwxMy4yODYsMTAuMDA3LDEyLjkyMyBNOS4wMjgsMTcuMDE2YzAuMTkxLTAuNTkyLDAuMjI2LTAuOTQzLDAuMy0xLjI4NUM4Ljc5NywxNi40MSw5LjA4NCwxNi41NTMsOS4wMjgsMTcuMDE2Ii8+PC9zdmc+Cg==0 + OS Family + Debian + + + Oracle Linux + image/svg+xmlicon-oracle-linux.svgPD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiIHhtbG5zOnNvZGlwb2RpPSJodHRwOi8vc29kaXBvZGkuc291cmNlZm9yZ2UubmV0L0RURC9zb2RpcG9kaS0wLmR0ZCIgeG1sbnM9Imh0dH + A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgMjMxIDIzMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pbllNaWQiIHZlcnNpb249IjEuMSIgaWQ9InN2ZzQiIHhtbDpzcGFjZT0icHJlc2VydmUiIHdpZHRoPSIyMzEiIGhlaWdodD0iMjMxIiBzb2RpcG9kaTpkb2NuYW1lPSJpY29uLW9yYWNsZS1saW51eC5zdmciIGlua3NjYXBlOnZlcnNpb249IjEuNC4zICgwZDE1Zjc1MDQyLCAy + MDI1LTEyLTI1KSI+PHNvZGlwb2RpOm5hbWVkdmlldyBpZD0ibmFtZWR2aWV3MSIgcGFnZWNvbG9yPSIjZmZmZmZmIiBib3JkZXJjb2xvcj0iIzAwMDAwMCIgYm9yZGVyb3BhY2l0eT0iMC4yNSIgaW5rc2NhcGU6c2hvd3BhZ2VzaGFkb3c9IjIiIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiIGlua3NjYXBlOnBhZ2VjaGVja2VyYm9hcmQ9IjAiIGlua3NjYXBlOmRlc2tjb2xvcj0iI2QxZDFkMSIgc2hvd2d1aWRlcz0idHJ1ZSIgaW5rc2NhcGU6em9vbT0iNy41MzMyOD + kxIiBpbmtzY2FwZTpjeD0iMTA3LjA1ODE1IiBpbmtzY2FwZTpjeT0iOTAuNzk2OTkzIiBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjI1NjAiIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjEzNjAiIGlua3NjYXBlOndpbmRvdy14PSIwIiBpbmtzY2FwZTp3aW5kb3cteT0iMCIgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSIgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ic3ZnNCI+PHNvZGlwb2RpOmd1aWRlIHBvc2l0aW9uPSI0MS43NjM1ODksMTE1LjQ2OCIgb3JpZW50 + YXRpb249IjAsLTEiIGlkPSJndWlkZTEiIGlua3NjYXBlOmxvY2tlZD0iZmFsc2UiLz48L3NvZGlwb2RpOm5hbWVkdmlldz48ZGVmcyBpZD0iZGVmczgiPjxyZWN0IHg9Ii0xMzguMjQ2NDEiIHk9IjgxLjU2NzIzOCIgd2lkdGg9IjM4Mi4zNjc0IiBoZWlnaHQ9IjI0MC4yMTE1NiIgaWQ9InJlY3Q0OTUiLz48cmVjdCB4PSItMTcuNjEyNjIzIiB5PSIxMDQuMzU4OTgiIHdpZHRoPSIxNzEuMDUyMzgiIGhlaWdodD0iMTk3LjMxNDQ0IiBpZD0icmVjdDI5MSIvPjwvZGVmcz + 48ZyBpZD0iZzE0MDciIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAuNjEzMjE1NDIsNzYuODM1NTMzKSI+PHBhdGggZD0ibSA5OS41OSwxOS41MiBoIDE1LjI0IEwgMTA2Ljc4LDYuNTIgOTEuOTgsMzAgaCAtNi43MyBsIDE4LC0yOC4xNyBhIDQuMjksNC4yOSAwIDAgMSA3LC0wLjA1IEwgMTI4LjMsMzAgaCAtNi43MyBsIC0zLjE3LC01LjI1IGggLTE1LjQyIGwgLTMuMzYsLTUuMjMgbSA2OS45Myw1LjIzIFYgMC4yOCBoIC01LjcyIHYgMjYuODggYSAyLjc2LDIuNzYgMCAw + IDAgMC44NSwyIDIuODksMi44OSAwIDAgMCAyLjA4LDAuODcgaCAyNiBsIDMuMzksLTUuMjUgaCAtMjYuNjMgbSAtOTQuNTQsLTQuNCBhIDEwLjA1LDEwLjA1IDAgMCAwIDAsLTIwLjEgaCAtMjUgViAzMCBoIDUuNzEgViA1LjU0IGggMTguOTQgYSA0LjgxLDQuODEgMCAwIDEgMCw5LjYyIEggNTguNTIgTCA3NS41OCwzMCBoIDguMjkgTCA3Mi40MSwyMC4zOCBoIDIuNTcgTSAxNC44NiwzMCBoIDE3LjI3IGEgMTQuODYsMTQuODYgMCAwIDAgMCwtMjkuNzEgSCAxNC44Ni + BhIDE0Ljg2LDE0Ljg2IDAgMSAwIDAsMjkuNzEgbSAxNi44OCwtNS4yMyBoIC0xNi41IGEgOS42Miw5LjYyIDAgMCAxIDAsLTE5LjIzIGggMTYuNSBhIDkuNjIsOS42MiAwIDEgMSAwLDE5LjIzIE0gMTQwLjIzLDMwIGggMTcuNjMgbCAzLjM0LC01LjIzIGggLTIwLjU4IGEgOS42Miw5LjYyIDAgMSAxIDAsLTE5LjIzIGggMTYuNzUgbCAzLjM4LC01LjI1IGggLTIwLjUyIGEgMTQuODYsMTQuODYgMCAxIDAgMCwyOS43MSBtIDY5Ljg3LC01LjIzIGEgOS42Miw5LjYyIDAg + MCAxIC05LjI2LC03IGggMjQuNDIgbCAzLjM2LC01LjI0IGggLTI3Ljc4IGEgOS42MSw5LjYxIDAgMCAxIDkuMjYsLTcgaCAxNi43NiBsIDMuMzUsLTUuMjUgaCAtMjAuNSBhIDE0Ljg2LDE0Ljg2IDAgMCAwIDAsMjkuNzEgaCAxNy42MyBsIDMuMzUsLTUuMjMgaCAtMjAuNiIgc3R5bGU9ImZpbGw6I2M3NDYzNCIgaWQ9InBhdGgyIi8+PHBhdGggaWQ9InJlY3Q3NDkiIHN0eWxlPSJmaWxsOiNjNzQ2MzQ7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlLXdpZHRoOjUuMjUxOTtzdH + Jva2UtbGluZWNhcDpzcXVhcmU7cGFpbnQtb3JkZXI6c3Ryb2tlIGZpbGwgbWFya2VycyIgZD0ibSAyNS4zOTE1MTcsNDcuOTMwODcxIGggNC45ODA4NjMgdiAzLjgzMDAyNSBoIC00Ljk4MDg2MyB6IG0gNjEuNTAwOCwxOC41NTcwNjEgLTcuMjQsLTEwLjI0MDAwMiBoIDQuOTYgbCA0LjY0LDcuMDgwMDAyIGggMC4yNCBsIDQuNzYsLTcuMDgwMDAyIGggNC43MiBsIC03LjI4LDEwLjE2MDAwMiA3LjY0LDEwLjg4IGggLTQuOTYgbCAtNS4wOCwtNy43MiBoIC0wLjI0IGwg + LTUuMTIsNy43MiBoIC00LjcyIHogbSAtMjEuNTk5OTk4LDExLjI4IHEgLTYuNjgsMCAtNi42OCwtNy4yNCBWIDU2LjI0NzkzIGggNC4xMiB2IDEzLjc2MDAwMiBxIDAsMi4zNiAxLjA0LDMuMzIgMS4wOCwwLjkyIDMuMTIsMC45MiAxLjQsMCAyLjYsLTAuNjggMS4yLC0wLjcyIDEuODgsLTIgMC43MiwtMS4yOCAwLjcyLC0yLjk2IFYgNTYuMjQ3OTMgaCA0LjEyIHYgMjEuMDQwMDAyIGggLTMuMzIgbCAtMC40LC0yLjggaCAtMC4yOCBxIC0xLjE2LDEuNiAtMi45MiwyLj + Q0IC0xLjc2LDAuODQgLTQsMC44NCB6IE0gMzUuODEyMzIsNTYuMjQ3OTMgaCAzLjMyMDAwMSBsIDAuNCwyLjgwMDAwMiBoIDAuMjggcSAxLjEyLC0xLjYwMDAwMiAyLjg4LC0yLjQ0MDAwMiAxLjgsLTAuODQgNC4wNCwtMC44NCA2LjY4LDAgNi42OCw3LjI0MDAwMiB2IDE0LjI4IGggLTQuMTIgdiAtMTMuNzYgcSAwLC0yLjM2IC0xLjA4LC0zLjI4IC0xLjA0LC0wLjk2IC0zLjA4LC0wLjk2IC0xLjQsMCAtMi42LDAuNzIgLTEuMiwwLjY4IC0xLjkyLDEuOTYgLTAuNjgsMS4yOCAtMC42OCwyLjk2IHYgMTIuMzYgSCAzNS44MTIzMiBaIE0gMy42MTIzOSw0Ny45MzA4NzEgaCA0LjQ0IHYgMjUuNTE3MDYxIGggMTQuMjggdiAzLjg0IGggLTE4LjcyIHogTSAyNi4yNTY3NjgsNTkuNDYzOTUgViA3Ny4yODc5MzIgSCAzMC4zNzIzOCBWIDU2LjI3NTQ2NCBoIC02LjM4NzYxMiB2IDEuODI1NjgxIHoiLz48L2c+PC9zdmc+Cg==0 + OS Family + Oracle Linux + + + Red Hat + image/svg+xmlicons8-red-hat.svgPD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNDggNDgiIHdpZHRoPSI0OHB4IiBoZWlnaHQ9IjQ4cHgiPjxwYXRoIGZpbGw9IiMzNzQ3NEYiIGQ9Ik0yNy44MTMsMzQuODg4Yy0wLjMxOSwwLjM1My0wLjc1NSwwLjM3OC0xLjI4NCwwLjA3NWMtMC40OTctMC4yODItMS4yN + zYtMC4yODItMS41MS0wLjAwMSBjLTAuMjY5LDAuMzIzLTAuMDc1LDAuNjgxLDAuMzY3LDAuNjgxYzAuMjA3LDAsMC42MDQsMC4xMzcsMC44NzQsMC4zMDNjMC4yNzEsMC4xNjcsMC42NTMsMC4zMDMsMC44NDcsMC4zMDMgYzAuNDc1LDAuMDAyLDEuMjM0LTAuNzgyLDEuMjM0LTEuMjczQzI4LjM0MiwzNC41MDYsMjguMTgyLDM0LjQ4LDI3LjgxMywzNC44ODh6IE00MywyNS45NzFjMCwzLjIyMS0wLjUzNSw1LjYwMi0xLjg4Nyw4LjM4NiBjLTAuOTgsMi4wMjItMC44NDY + sMS45Mi0yLjI3MiwxLjc0Yy0xLjI5My0wLjE2My0yLjk4OS0wLjAyNi00LjA3NSwwLjMzMWMtMC40ODQsMC4xNi0wLjYxNywwLjI4My0wLjY4MSwwLjY0MyBjLTAuMDY1LDAuMzc5LTAuMjA2LDAuNDkzLTAuOTc5LDAuNzkzYy0wLjY1MiwwLjI1My0wLjk3NywxLjAzMy0xLjY4NiwxLjcyOGMtMC41NDMsMC41My0xLjEyMSwxLjAzLTEuMjg4LDEuMTEzIEMyOS43NDIsNDAuODk0LDI5LDQxLjA2OSwyOSw0MC45NzRjMC0wLjA3MSwwLjk4Ni0yLjI1MSwyLjM1Ny00LjIxO + GMwLjQ5LTAuNzA0LDAuNjYxLTEuMTA0LDAuNzA5LTEuNjYxIGMwLjAzNi0wLjQwNSwwLjIxMS0xLjIyOSwwLjM4OS0xLjgzYzAuMTc5LTAuNjAzLDAuMjg5LTEuMTMsMC4yNDYtMS4xNzNzLTAuMzcsMC4wMjUtMC43MjYsMC4xNDggYy0wLjc3OSwwLjI3NS0xLjI5MywwLjI4Ni0yLjE3NywwLjA1MWMtMC41NjMtMC4xNTEtMC43NzEtMC4xMzktMS4zNDQsMC4wOGMtMC42MzksMC4yNDYtMC43MTksMC4yNDYtMS4zMTMsMC4wMDYgYy0wLjU5NS0wLjIzNy0wLjcyNS0wLjI + zNy0yLjE0NiwwLjAxNGMtMi42NTUsMC40NjYtMy41MTMsMC4yMDYtNS4yODQtMS42MDljLTEuMDk4LTEuMTI1LTEuNTA4LTEuMzcyLTEuNzE3LTEuMDMgYy0wLjA1MSwwLjA4My0wLjI1MywwLjE1MS0wLjQ0NiwwLjE1MWMtMC4yNTgsMC0wLjQ4NC0wLjIwMy0wLjg0MS0wLjc2Yy0wLjI2Ny0wLjQxNS0wLjY3Ny0wLjg5My0wLjkwOS0xLjA1OCBjLTEuMjc0LTAuOTA2LTIuNzE1LTAuMjUtMi43MTUsMS4yNGMwLDAuNjE0LDEuMjI4LDIuNDY1LDEuODQ3LDIuNzg2YzAuO + DE4LDAuNDIzLDAuMzU3LDEuMDU3LTAuNjcxLDAuOTE5IGMtMC41MzItMC4wNzItMC43NjctMC4yMzEtMS40ODItMS4wMDNjLTAuNzY0LTAuODI2LTAuOTA3LTAuOTE2LTEuNDQzLTAuOTE0Yy0wLjMyOCwwLjAwMi0wLjg3NSwwLjEzMS0xLjIxNSwwLjI4NCBjLTAuODc3LDAuMzk5LTIuMDIyLDAuNjItMy4yMjEsMC42Mkg1Ljg2NUw1LjYzLDMxLjE0NkM1LjA5MywyOS4xNzEsNSwyOC40LDUsMjUuOTcxYzAtMS44NTcsMC4wNzEtMi44MjEsMC4yNzktMy43NzkgYzEuMTI + 0LTUuMTcyLDMuOTg0LTkuMzUzLDguMzIzLTEyLjE2OWMyLjEyOC0xLjM4Miw0LjA4NC0yLjE5Miw2LjU3OS0yLjcyOWMxLjc4My0wLjM4Myw1Ljc3Ni0wLjM5NCw3LjUxLTAuMDIxIGM1LjkwMiwxLjI3MywxMC43OTQsNC45OTYsMTMuMzM5LDEwLjE2QzQyLjQ1NywyMC4zMjUsNDMsMjIuNjc3LDQzLDI1Ljk3MXoiLz48cGF0aCBmaWxsPSIjRkYzRDAwIiBkPSJNMzguMDgyLDIyLjMxMmMtMC43MTEtMC41MzktMi41MjktMS4zMjctMy4wNjMtMS4zMjdjLTAuMTQ2LDAtM + C40LDAuMjczLTAuNTk4LDAuNjQzIGMtMC4yOTcsMC41NTktMS4xMzEsMS4zMjItMS40NDQsMS4zMjJjLTAuMDU4LDAsMC4xMDEtMC4zODQsMC4zNS0wLjg1MmMwLjExLTAuMjA1LDAuMjA0LTAuNDIzLDAuMjgtMC42MzEgYzAuMTA5LTAuMzAzLDAuMTc4LTAuNTg0LDAuMTc4LTAuNzc2YzAtMC45NTgtMC42NzYtMy4xMTctMS40OTctNS4wNDljLTAuNDM1LTEuMDI0LTAuOTExLTEuOTg1LTEuMzUxLTIuNjY5IGMtMC4yMTUtMC4zMzUtMC4zOTMtMC41ODktMC41NTktMC4 + 3OTJjLTAuMjktMC4zNTEtMC41NTktMC41NTQtMC45NzUtMC43NzljLTAuMjgzLTAuMTUyLTAuNTgtMC4yNy0wLjg5MS0wLjM1NiBjLTAuMDA2LDAtMC4wMTItMC4wMDMtMC4wMTYtMC4wMDNjLTAuMDczLTAuMDIxLTAuMTQ1LTAuMDM5LTAuMjE5LTAuMDU1Yy0wLjAxMi0wLjAwMy0wLjAyMy0wLjAwNS0wLjAzNS0wLjAwOSBjLTAuMDctMC4wMTQtMC4xMzktMC4wMjYtMC4yMTItMC4wMzljLTAuMDE1LTAuMDAzLTAuMDI4LTAuMDAzLTAuMDQ0LTAuMDA2Yy0wLjA3Mi0wL + jAxMi0wLjE0Mi0wLjAyMS0wLjIxNS0wLjAzIGMtMC4wMTItMC4wMDEtMC4wMjUtMC4wMDEtMC4wMzctMC4wMDNjLTAuMTYtMC4wMTYtMC4zMjUtMC4wMjctMC40OTUtMC4wMjdjLTAuMDE3LDAtMC4wMzYsMC0wLjA1MywwIGMtMC4xMiwwLTAuMjM5LDAuMDA2LTAuMzYyLDAuMDE0Yy0wLjAzOSwwLjAwMS0wLjA3NiwwLjAwNC0wLjExNCwwLjAwNWMtMC4xMzIsMC4wMTEtMC4yNjcsMC4wMjQtMC40MDIsMC4wNDIgYy0wLjA0OCwwLjAwNi0wLjA5NSwwLjAxMy0wLjE0NCw + wLjAxOWMtMC4xMzQsMC4wMTktMC4yNywwLjA0MS0wLjQwOCwwLjA2OGMtMC4wNTUsMC4wMS0wLjExMiwwLjAyNC0wLjE3LDAuMDM2IGMtMC4xMDYsMC4wMjItMC4yMTgsMC4wNDgtMC4zMjksMC4wNzVjLTAuMDQzLDAuMDEtMC4wODMsMC4wMTctMC4xMjYsMC4wMjdjLTEuMDYzLDAuMjcyLTEuNTU4LDAuMzE5LTIuNTY2LDAuMjQ1IGMtNC4xMTctMC4yOTctMy45NTEtMC4zLTQuNjMsMC4wNDdjLTAuMzY4LDAuMTg4LTAuNjI4LDAuMzktMC44NDgsMC43M2MtMC4yOTgsM + C40NjItMC41MiwxLjE3Mi0wLjgyOSwyLjQ1MSBjLTAuNTgyLDIuNDAzLTAuNTk1LDMuMTQ2LTAuMDY4LDMuNzczYzAuNTM2LDAuNjM5LDIuMjY1LDEuNDMxLDMuOTksMS44MjdjMi4wNjMsMC40NzQsMy40NjksMC44OTIsMy44NTksMS4xNDkgYzAuMDk3LDAuMDYzLDAuMjA1LDAuMTc4LDAuMzAxLDAuMzEzYzAuMDkxLDAuMTI1LDAuMTcsMC4yNjYsMC4yMTgsMC4zOTRjMC40MzQsMS4xNTcsMC42NjcsMS42MjcsMC45MzEsMS44NjQgYzAuMDY1LDAuMDYsMC4xMjUsMC4 + xMzEsMC4xNzQsMC4xOTdjMC4wNjYsMC4wOTIsMC4xMDcsMC4xODMsMC4xMDcsMC4yMzljMCwxLjA5Ny03LjgwMy0xLjMzMy05LjgxNC0zLjA1NCBjLTAuNTM4LTAuNDYyLTAuODM3LTAuODQ2LTAuOTY1LTEuMjg4Yy0wLjA3Ny0wLjI3NC0wLjA4Ny0wLjU3MS0wLjA0Ni0wLjkyMmwwLjAyNC0wLjIxMWwwLjA2My0wLjUzNGgtMC4wMDF2LTAuMDAybC0xLjk5OCwwLjA2NiBjLTEuNjg4LDAuMDU2LTIuMTA5LDAuMTE4LTIuNzE1LDAuNDEyYy0yLjA4NiwxLjAwNS0xLjk4N + SwyLjY5LDAuMjg4LDQuODVjMS42MzQsMS41NTQsNC4xMTMsMy4wODUsNi44NTMsNC4zMzQgYzIuODI4LDEuMjkzLDUuOTM2LDIuMjgzLDguNjgxLDIuNjg2YzEuMTg4LDAuMTc1LDIuNzEyLDAuMjM3LDQuMTEzLDAuMTkzYzAuNzkxLTAuMDI0LDEuNTQzLTAuMDg0LDIuMTctMC4xOCBjMy4zNjUtMC41MTMsNS42OTUtMS44ODYsNi42NjgtMy45MzRjMC4xMDUtMC4yMjIsMC4xODktMC40MzgsMC4yNTgtMC42NTJDMzkuODE4LDI0LjY1NCwzOS4zNzcsMjMuMjk3LDM4LjA + 4MiwyMi4zMTJ6IE0yMi4xMjIsMTYuMDE1Yy0xLjQzOCwwLjE1OS0yLjE0MSwwLjM1NS0yLjQwMywwLjY3MWMtMC4xMDEsMC4xMjEtMC4yMDQsMC4xODgtMC4zMjcsMC4xOTdjLTAuMjQ5LDAuMDE3LTAuNTctMC4yMTUtMS4wODktMC43NDIgYy0wLjM2MS0wLjM3MS0wLjU2Ny0wLjYzNy0wLjY2Ny0wLjg2N2MtMC4wNS0wLjExNS0wLjA3My0wLjIyNi0wLjA3My0wLjMzMmMwLTAuMDYxLDAuMDA0LTAuMTIsMC4wMS0wLjE3OCBjMC4wMDEtMC4wMDgsMC4wMDMtMC4wMTYsM + C4wMDMtMC4wMjNjMC4wMDctMC4wNDcsMC4wMTYtMC4wOTMsMC4wMjgtMC4xMzljMC4wMDEtMC4wMDksMC4wMDMtMC4wMTUsMC4wMDUtMC4wMjMgYzAuMDE0LTAuMDQ4LDAuMDI5LTAuMDk0LDAuMDQ5LTAuMTM3YzAuMDAzLTAuMDA3LDAuMDA1LTAuMDEzLDAuMDEtMC4wMTljMC4wMTctMC4wMzIsMC4wMzItMC4wNjMsMC4wNTEtMC4wOTMgYzAuMDA3LTAuMDEzLDAuMDE1LTAuMDI0LDAuMDIzLTAuMDM1YzAuMDE0LTAuMDI0LDAuMDMyLTAuMDQ2LDAuMDUtMC4wNjdjMC4 + wMDctMC4wMDksMC4wMTUtMC4wMTcsMC4wMjMtMC4wMjcgYzAuMDI1LTAuMDI0LDAuMDUxLTAuMDQ3LDAuMDc3LTAuMDY1YzAuMDEyLTAuMDA3LDAuMDIzLTAuMDE1LDAuMDM2LTAuMDJjMC4wMTktMC4wMTQsMC4wMzgtMC4wMjEsMC4wNTgtMC4wMyBjMC4wMTItMC4wMDYsMC4wMjUtMC4wMTEsMC4wMzctMC4wMTVjMC4wMjktMC4wMDgsMC4wNTctMC4wMTYsMC4wODgtMC4wMTljMC4wMDMsMCwwLjAwNi0wLjAwMSwwLjAxLTAuMDAxIGMwLjAzMi0wLjAwMywwLjA2NC0wL + jAwMiwwLjA5NywwLjAwM2MwLjAwNywwLjAwMSwwLjAxNSwwLjAwMywwLjAyMywwLjAwNGMwLjAyNiwwLjAwNiwwLjA1MywwLjAxMiwwLjA3OSwwLjAyMSBjMC4wMDcsMC4wMDMsMC4wMTQsMC4wMDYsMC4wMjEsMC4wMDljMC4wMzEsMC4wMTQsMC4wNjIsMC4wMzEsMC4wOTEsMC4wNTFjMC4wMDIsMC4wMDIsMC4wMDQsMC4wMDMsMC4wMDcsMC4wMDYgYzAuMDM2LDAuMDIzLDAuMDcxLDAuMDUsMC4xMDQsMC4wODNjMC42NjgsMC42NTMsMC45LDAuNzE0LDIuMzk0LDAuNjE + 1YzAuNTQ2LTAuMDM3LDEuMDEyLTAuMDM4LDEuMzk0LTAuMDA3IGMwLjcwOSwwLjA2LDEuMTMxLDAuMjMsMS4yNCwwLjUxNWMwLjAzOCwwLjA5OSwwLjA1LDAuMTgsMC4wMjUsMC4yNUMyMy41MjIsMTUuODA5LDIzLjEyMiwxNS45MDQsMjIuMTIyLDE2LjAxNXogTTI5LjAwMSwxMy4zOCBjLTAuMDEsMC4wMDctMC4wMTksMC4wMTMtMC4wMzEsMC4wMTljMCwwLjAwMS0wLjAwMywwLjAwMy0wLjAwNiwwLjAwNGMtMC41MTEsMC4yNjktMS4zMjUsMC40MjktMi4xNzEsMC4zN + TggYy0wLjM0NC0wLjAyNy0wLjUyNi0wLjA4Ny0wLjU0My0wLjE2NGMtMC4wMTItMC4wNTIsMC4wNTUtMC4xMTEsMC4xOTctMC4xNzFjMC4wNy0wLjAzLDAuMTUzLTAuMDYxLDAuMjU2LTAuMDg5IGMwLjU4NC0wLjE2OSwwLjkxLTAuNjA4LDAuNTk0LTAuODA1Yy0wLjMzNy0wLjIxMi0xLjQ5Mi0wLjM0NS0yLjAwNC0wLjIzMWMtMC4yMTcsMC4wNDktMC4zNDIsMC4wNTEtMC4zNzQsMC4wMTMgYy0wLjAwMS0wLjAwMS0wLjAwNC0wLjAwMy0wLjAwNS0wLjAwNmMtMC4wMDk + tMC4wMTUtMC4wMDQtMC4wMzUsMC4wMTEtMC4wNjJjMC4wMTItMC4wMTYsMC4wMjYtMC4wMzEsMC4wNDctMC4wNDggYzAsMCwwLjAwMSwwLDAuMDAyLDBjMC4wMTktMC4wMTgsMC4wNDUtMC4wMzIsMC4wNzItMC4wNDZjMC4wMDItMC4wMDMsMC4wMDYtMC4wMDMsMC4wMS0wLjAwNmMwLjAyNy0wLjAxNCwwLjA1Ny0wLjAyNywwLjA5Mi0wLjA0MSBjMC4wMDUtMC4wMDIsMC4wMDgtMC4wMDMsMC4wMTEtMC4wMDVjMC4wMzctMC4wMTQsMC4wNzctMC4wMjgsMC4xMjEtMC4wN + DJjMC4wMDEsMCwwLjAwMy0wLjAwMiwwLjAwNS0wLjAwMiBjMC4yNzYtMC4wOSwwLjY4Mi0wLjE2NCwxLjEtMC4yMTNjMC4wMDgtMC4wMDMsMC4wMTQtMC4wMDMsMC4wMjEtMC4wMDNjMC4wNjEtMC4wMDksMC4xMjMtMC4wMTQsMC4xODYtMC4wMiBjMC4wMDktMC4wMDIsMC4wMTktMC4wMDIsMC4wMjctMC4wMDNjMC4wNjEtMC4wMDQsMC4xMTktMC4wMDksMC4xOC0wLjAxM2MwLjAwOSwwLDAuMDE5LTAuMDAyLDAuMDI3LTAuMDAyIGMwLjA2NS0wLjAwMywwLjEzMS0wLjAwNywwLjE5My0wLjAwOWMwLjAwNCwwLDAuMDA2LDAsMC4wMDYsMGMwLjIwNi0wLjAwOCwwLjQtMC4wMDIsMC41NzEsMC4wMTIgYzAuOTQ4LDAuMDg2LDEuNzE2LDAuNDIxLDEuODY4LDAuODEzYzAuMDE1LDAuMDQsMC4wMjQsMC4wOCwwLjAyNywwLjEyM0MyOS41MSwxMi45NzksMjkuMzIsMTMuMjAxLDI5LjAwMSwxMy4zOHoiLz48L3N2Zz4K0 + OS Family + Red Hat + + + Ubuntu + image/svg+xmlicons8-ubuntu.svgPD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNDggNDgiIHdpZHRoPSI0OHB4IiBoZWlnaHQ9IjQ4cHgiPjxwYXRoIGZpbGw9IiNmZmYiIGQ9Ik00MCwyNGMwLDguOC03LjIsMTYtMTYsMTZTOCwzMi44LDgsMjRTMTUuMiw4LDI0LDhTNDAsMTUuMiw0MCwyNHoiLz48cGF0aC + BmaWxsPSIjZTY0YTE5IiBkPSJNMzAgMjRjMCAzLjMtMi43IDYtNiA2LTMuMyAwLTYtMi43LTYtNnMyLjctNiA2LTZDMjcuMyAxOCAzMCAyMC43IDMwIDI0ek0xMiAyMS41YzEuNCAwIDIuNSAxLjEgMi41IDIuNXMtMS4xIDIuNS0yLjUgMi41UzkuNSAyNS40IDkuNSAyNCAxMC42IDIxLjUgMTIgMjEuNU0xMiAyMC41Yy0xLjkgMC0zLjUgMS42LTMuNSAzLjVzMS42IDMuNSAzLjUgMy41IDMuNS0xLjYgMy41LTMuNVMxMy45IDIwLjUgMTIgMjAuNXpNMzAgMzEuNWMxLjQg + MCAyLjUgMS4xIDIuNSAyLjVzLTEuMSAyLjUtMi41IDIuNS0yLjUtMS4xLTIuNS0yLjVTMjguNiAzMS41IDMwIDMxLjVNMzAgMzAuNWMtMS45IDAtMy41IDEuNi0zLjUgMy41czEuNiAzLjUgMy41IDMuNSAzLjUtMS42IDMuNS0zLjVTMzEuOSAzMC41IDMwIDMwLjV6Ii8+PHBhdGggZmlsbD0iI2U2NGExOSIgZD0iTTI0LDRDMTMsNCw0LDEzLDQsMjRzOSwyMCwyMCwyMHMyMC05LDIwLTIwUzM1LDQsMjQsNHogTTMyLjUsMzRjMCwxLjQtMS4xLDIuNS0yLjUsMi41IHMtMi + 41LTEuMS0yLjUtMi41YzAtMC4yLDAtMC41LDAuMS0wLjdDMjYuNSwzMy44LDI1LjMsMzQsMjQsMzRjLTUuMSwwLTkuMi0zLjgtOS45LTguN2MtMC40LDAuNy0xLjIsMS4yLTIuMSwxLjIgYy0xLjQsMC0yLjUtMS4xLTIuNS0yLjVzMS4xLTIuNSwyLjUtMi41YzAuOSwwLDEuNywwLjUsMi4xLDEuMmMwLjctNC45LDQuOC04LjcsOS45LTguN2MxLjMsMCwyLjUsMC4yLDMuNiwwLjcgYy0wLjEtMC4yLTAuMS0wLjQtMC4xLTAuN2MwLTEuNCwxLjEtMi41LDIuNS0yLjVzMi41 + LDEuMSwyLjUsMi41YzAsMS4yLTAuOCwyLjItMiwyLjRDMzIuNywxOC4zLDM0LDIxLDM0LDI0cy0xLjMsNS43LTMuNSw3LjYgQzMxLjcsMzEuOCwzMi41LDMyLjgsMzIuNSwzNHoiLz48cGF0aCBmaWxsPSIjZTY0YTE5IiBkPSJNMzAgMTEuNWMxLjQgMCAyLjUgMS4xIDIuNSAyLjUgMCAxLjQtMS4xIDIuNS0yLjUgMi41cy0yLjUtMS4xLTIuNS0yLjVDMjcuNSAxMi42IDI4LjYgMTEuNSAzMCAxMS41TTMwIDEwLjVjLTEuOSAwLTMuNSAxLjYtMy41IDMuNXMxLjYgMy41ID + MuNSAzLjUgMy41LTEuNiAzLjUtMy41UzMxLjkgMTAuNSAzMCAxMC41ek0yNCAyNGMtMi42LTQuMS01LjItOC4xLTcuOC0xMi4yIi8+PHBhdGggZmlsbD0iI2U2NGExOSIgZD0iTTE5LjEgMTAuN0gyMS4xVjI1LjFIMTkuMXoiIHRyYW5zZm9ybT0icm90YXRlKC0zMi40NjcgMjAuMTI3IDE3LjkxMSkiLz48cGF0aCBmaWxsPSIjZTY0YTE5IiBkPSJNMjQgMjNIMzguNFYyNUgyNHoiLz48Zz48cGF0aCBmaWxsPSIjZTY0YTE5IiBkPSJNMjQsMjRjLTIuNyw0LTUuMyw4LTgsMTIiLz48cGF0aCBmaWxsPSIjZTY0YTE5IiBkPSJNMTIuOCAyOUgyNy4yMDAwMDAwMDAwMDAwMDNWMzFIMTIuOHoiIHRyYW5zZm9ybT0icm90YXRlKC01Ni4zMTIgMTkuOTk4IDMwLjAwNikiLz48L2c+PC9zdmc+Cg==0 + OS Family + Ubuntu + + + Ubuntu server + image/svg+xmlicons8-ubuntu.svgPD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNDggNDgiIHdpZHRoPSI0OHB4IiBoZWlnaHQ9IjQ4cHgiPjxwYXRoIGZpbGw9IiNmZmYiIGQ9Ik00MCwyNGMwLDguOC03LjIsMTYtMTYsMTZTOCwzMi44LDgsMjRTMTUuMiw4LDI0LDhTNDAsMTUuMiw0MCwyNHoiLz48cGF0aC + BmaWxsPSIjZTY0YTE5IiBkPSJNMzAgMjRjMCAzLjMtMi43IDYtNiA2LTMuMyAwLTYtMi43LTYtNnMyLjctNiA2LTZDMjcuMyAxOCAzMCAyMC43IDMwIDI0ek0xMiAyMS41YzEuNCAwIDIuNSAxLjEgMi41IDIuNXMtMS4xIDIuNS0yLjUgMi41UzkuNSAyNS40IDkuNSAyNCAxMC42IDIxLjUgMTIgMjEuNU0xMiAyMC41Yy0xLjkgMC0zLjUgMS42LTMuNSAzLjVzMS42IDMuNSAzLjUgMy41IDMuNS0xLjYgMy41LTMuNVMxMy45IDIwLjUgMTIgMjAuNXpNMzAgMzEuNWMxLjQg + MCAyLjUgMS4xIDIuNSAyLjVzLTEuMSAyLjUtMi41IDIuNS0yLjUtMS4xLTIuNS0yLjVTMjguNiAzMS41IDMwIDMxLjVNMzAgMzAuNWMtMS45IDAtMy41IDEuNi0zLjUgMy41czEuNiAzLjUgMy41IDMuNSAzLjUtMS42IDMuNS0zLjVTMzEuOSAzMC41IDMwIDMwLjV6Ii8+PHBhdGggZmlsbD0iI2U2NGExOSIgZD0iTTI0LDRDMTMsNCw0LDEzLDQsMjRzOSwyMCwyMCwyMHMyMC05LDIwLTIwUzM1LDQsMjQsNHogTTMyLjUsMzRjMCwxLjQtMS4xLDIuNS0yLjUsMi41IHMtMi + 41LTEuMS0yLjUtMi41YzAtMC4yLDAtMC41LDAuMS0wLjdDMjYuNSwzMy44LDI1LjMsMzQsMjQsMzRjLTUuMSwwLTkuMi0zLjgtOS45LTguN2MtMC40LDAuNy0xLjIsMS4yLTIuMSwxLjIgYy0xLjQsMC0yLjUtMS4xLTIuNS0yLjVzMS4xLTIuNSwyLjUtMi41YzAuOSwwLDEuNywwLjUsMi4xLDEuMmMwLjctNC45LDQuOC04LjcsOS45LTguN2MxLjMsMCwyLjUsMC4yLDMuNiwwLjcgYy0wLjEtMC4yLTAuMS0wLjQtMC4xLTAuN2MwLTEuNCwxLjEtMi41LDIuNS0yLjVzMi41 + LDEuMSwyLjUsMi41YzAsMS4yLTAuOCwyLjItMiwyLjRDMzIuNywxOC4zLDM0LDIxLDM0LDI0cy0xLjMsNS43LTMuNSw3LjYgQzMxLjcsMzEuOCwzMi41LDMyLjgsMzIuNSwzNHoiLz48cGF0aCBmaWxsPSIjZTY0YTE5IiBkPSJNMzAgMTEuNWMxLjQgMCAyLjUgMS4xIDIuNSAyLjUgMCAxLjQtMS4xIDIuNS0yLjUgMi41cy0yLjUtMS4xLTIuNS0yLjVDMjcuNSAxMi42IDI4LjYgMTEuNSAzMCAxMS41TTMwIDEwLjVjLTEuOSAwLTMuNSAxLjYtMy41IDMuNXMxLjYgMy41ID + MuNSAzLjUgMy41LTEuNiAzLjUtMy41UzMxLjkgMTAuNSAzMCAxMC41ek0yNCAyNGMtMi42LTQuMS01LjItOC4xLTcuOC0xMi4yIi8+PHBhdGggZmlsbD0iI2U2NGExOSIgZD0iTTE5LjEgMTAuN0gyMS4xVjI1LjFIMTkuMXoiIHRyYW5zZm9ybT0icm90YXRlKC0zMi40NjcgMjAuMTI3IDE3LjkxMSkiLz48cGF0aCBmaWxsPSIjZTY0YTE5IiBkPSJNMjQgMjNIMzguNFYyNUgyNHoiLz48Zz48cGF0aCBmaWxsPSIjZTY0YTE5IiBkPSJNMjQsMjRjLTIuNyw0LTUuMyw4LTgsMTIiLz48cGF0aCBmaWxsPSIjZTY0YTE5IiBkPSJNMTIuOCAyOUgyNy4yMDAwMDAwMDAwMDAwMDNWMzFIMTIuOHoiIHRyYW5zZm9ybT0icm90YXRlKC01Ni4zMTIgMTkuOTk4IDMwLjAwNikiLz48L2c+PC9zdmc+Cg==0 + OS Family + Ubuntu server + + + vCenter Server + image/svg+xmlicons8-vmware.svgPD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNTAgNTAiIHdpZHRoPSI1MHB4IiBoZWlnaHQ9IjUwcHgiPjxwYXRoIGQ9Ik0gNDIuNDE0MDYzIDE1IEMgMzguODI0MjE5IDE1IDM2LjU3NDIxOSAxNy41IDM2LjU3NDIxOSAxNy41IEMgMzUuMzc4OTA2IDE1Ljk0MTQwNiAzMy43MzA0NjkgMTUuMDAzOTA2IDMwLjk0MTQwNiAxNS4wMDM5MDYgQyAyNy45OTYwOTQgMTUuMDAzOTA2IDI2LjA0Mjk2OSAxNy41IDI2LjA0Mjk2OSAxNy41IEMgMjQuODQ3NjU2IDE1Ljk0MTQwNiAyMi42ODc1IDE1IDIxIDE1IEMgMTguMzkwNjI1IDE1IDE2LjMyMDMxMyAxNi4xNTIzNDQgMTUuMDU0Njg4IDE5LjA1ODU5NCBMIDEwLjgyMDMxMyAyOC4zMjAzMTMgTCA2LjAzMTI1IDE2LjU1ODU5NCBDIDUuNDI1NzgxIDE1LjIyNjU2MyAzLjkzMzU5NCAxNC42MjUgMi41NDI5NjkgMTUuMjQ2MDk0IEMgMS4xNDg0MzggMTUuODcxMDk0IDAuNjM2NzE5IDE3LjQyNTc4MSAxLjI2NTYyNSAxOC43NTc4MTMgTCA3LjExMzI4MSAzMS45NDUzMTMgQyA4LjAzMTI1IDMzLjk0OTIxOSA5LjAwMzkwNiAzNSAxMC44MjAzMTMgMzUgQyAxMi43NjU2MjUgMzUgMTMuNjA5Mzc1IDMzLjg1NTQ2OSAxNC41MzEyNSAzMS45NDUzMTMgQyAxNC41MzEyNSAzMS45NDUzMTMgMTguNTExNzE5IDIzLjA2MjUgMTkgMjIgQyAxOS40ODgyODEgMjAuOTM3NSAyMC4zMDA3ODEgMjAgMjEuNSAyMCBDIDIyLjg3NSAyMCAyNCAyMS4xMjUgMjQgMjIuNSBMIDI0IDMyLjM3NSBDIDI0IDMzLjgyMDMxMyAyNS4wODU5MzggMzUgMjYuNTIzNDM4IDM1IEMgMjcuOTU3MDMxIDM1IDI5IDMzLjgyMDMxMyAyOSAzMi4zNzUgTCAyOSAyMi41IEMgMjkgMjEuMTI1IDMwLjEyNSAyMCAzMS41IDIwIEMgMzIuODc1IDIwIDM0IDIxLjEyNSAzNCAyMi41IEwgMzQgMzIuNSBDIDM0IDMzLjg3NSAzNS4xMjUgMzUgMzYuNSAzNSBDIDM3Ljg3NSAzNSAzOSAzMy44NzUgMzkgMzIuNSBMIDM5IDIyLjUgQyAzOSAyMS4xMjUgNDAuMTI1IDIwIDQxLjUgMjAgQyA0Mi44NzUgMjAgNDQgMjEuMTI1IDQ0IDIyLjUgTCA0NCAzMi41IEMgNDQgMzMuODc1IDQ1LjEyNSAzNSA0Ni41IDM1IEMgNDcuODc1IDM1IDQ5IDMzLjg3NSA0OSAzMi41IEwgNDkgMjEuMzU1NDY5IEMgNDkgMTcuNjE3MTg4IDQ2LjAxMTcxOSAxNSA0Mi40MTQwNjMgMTUgWiIvPjwvc3ZnPgo=0 + OS Family + vCenter Server + + + Windows + image/svg+xmlicons8-windows.svgPD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNDggNDgiIHdpZHRoPSI0OHB4IiBoZWlnaHQ9IjQ4cHgiPjxwYXRoIGZpbGw9IiMxOTc2ZDIiIGQ9Ik02LDZoMTd2MTdINlY2eiIvPjxwYXRoIGZpbGw9IiMxOTc2ZDIiIGQ9Ik0yNS4wNDIsMjIuOTU4VjZINDJ2MTYuOTU4SDI1LjA0MnoiLz48cGF0aCBmaWxsPSIjMTk3NmQyIiBkPSJNNiwyNWgxN3YxN0g2VjI1eiIvPjxwYXRoIGZpbGw9IiMxOTc2ZDIiIGQ9Ik0yNSw0MlYyNWgxN3YxN0gyNXoiLz48L3N2Zz4K0 + OS Family + Windows + + + Windows server + image/svg+xmlicons8-windows-server.svgPD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNDggNDgiIHdpZHRoPSI0OHB4IiBoZWlnaHQ9IjQ4cHgiPjxwYXRoIGZpbGw9IiMwMGIwZmYiIGQ9Ik0yMCAyNS4wMjZMNS4wMTEgMjUgNS4wMTIgMzcuNzQ0IDIwIDM5LjgxOHpNMjIgMjUuMDNMMjIgNDAuMDk1IDQyLjk5NSA0MyA0MyAyNS4wNjZ6TTIwIDguMjU2TDUgMTAuMzggNS4wMTQgMjMgMjAgMjN6TTIyIDcuOTczTDIyIDIzIDQyLjk5NSAyMyA0Mi45OTUgNXoiLz48L3N2Zz4K0 + OS Family + Windows server + + diff --git a/datamodels/2.x/itop-config-mgmt/datamodel.itop-config-mgmt.xml b/datamodels/2.x/itop-config-mgmt/datamodel.itop-config-mgmt.xml index 1a919805d..27f43a136 100755 --- a/datamodels/2.x/itop-config-mgmt/datamodel.itop-config-mgmt.xml +++ b/datamodels/2.x/itop-config-mgmt/datamodel.itop-config-mgmt.xml @@ -1065,23 +1065,8 @@
- - 10 - - - 20 - - - 35 - - - 40 - - - 50 - - 80 + 10 10 @@ -1144,7 +1129,7 @@ - 90 + 20 10 @@ -1184,6 +1169,21 @@ + + 70 + + + 80 + + + 90 + + + 100 + + + 110 +
@@ -1717,24 +1717,44 @@
- + + + + + + 10 + + + 20 + + + 30 + + + 40 + + + 10 + + 10 - + + + + + + 50 + + + 60 + + + 10 + + 20 - - 30 - - - 40 - - - 50 - - - 60 - 70 @@ -1874,24 +1894,44 @@
- + + + + + + 10 + + + 20 + + + 30 + + + 40 + + + 10 + + 10 - + + + + + + 50 + + + 60 + + + 10 + + 20 - - 30 - - - 40 - - - 50 - - - 60 - 70 @@ -2194,36 +2234,66 @@
- + + + + + + 10 + + + 20 + + + 30 + + + 40 + + + 10 + + + + + 50 + + + 60 + + + 70 + + + 80 + + + 20 + + 10 - + + + + + + 90 + + + 10 + + + + + 100 + + + 20 + + 20 - - 30 - - - 40 - - - 50 - - - 60 - - - 70 - - - 80 - - - 90 - - - 100 - 110 @@ -2348,36 +2418,66 @@
- + + + + + + 10 + + + 20 + + + 30 + + + 40 + + + 10 + + + + + 50 + + + 60 + + + 70 + + + 80 + + + 20 + + 10 - + + + + + + 90 + + + 10 + + + + + 100 + + + 20 + + 20 - - 30 - - - 40 - - - 50 - - - 60 - - - 70 - - - 80 - - - 90 - - - 100 - 110 @@ -2502,36 +2602,66 @@
- + + + + + + 10 + + + 20 + + + 30 + + + 40 + + + 10 + + + + + 50 + + + 60 + + + 70 + + + 80 + + + 20 + + 10 - + + + + + + 90 + + + 10 + + + + + 100 + + + 20 + + 20 - - 30 - - - 40 - - - 50 - - - 60 - - - 70 - - - 80 - - - 90 - - - 100 - 110 @@ -2648,36 +2778,66 @@
- + + + + + + 10 + + + 20 + + + 30 + + + 40 + + + 10 + + + + + 50 + + + 60 + + + 70 + + + 80 + + + 20 + + 10 - + + + + + + 90 + + + 10 + + + + + 100 + + + 20 + + 20 - - 30 - - - 40 - - - 50 - - - 60 - - - 70 - - - 80 - - - 90 - - - 100 - 110 @@ -2781,36 +2941,66 @@
- + + + + + + 10 + + + 20 + + + 30 + + + 40 + + + 10 + + + + + 50 + + + 60 + + + 70 + + + 80 + + + 20 + + 10 - + + + + + + 90 + + + 10 + + + + + 100 + + + 20 + + 20 - - 30 - - - 40 - - - 50 - - - 60 - - - 70 - - - 80 - - - 90 - - - 100 - 110 @@ -2927,24 +3117,49 @@
- + + + + + + 10 + + + 20 + + + 40 + + + 10 + + + + + 30 + + + 20 + + 10 - + + + + + + 50 + + + 60 + + + 10 + + 20 - - 30 - - - 40 - - - 50 - - - 60 - 70 @@ -3064,24 +3279,49 @@
- + + + + + + 10 + + + 20 + + + 40 + + + 10 + + + + + 10 + + + 20 + + 10 - + + + + + + 50 + + + 60 + + + 10 + + 20 - - 30 - - - 40 - - - 50 - - - 60 - 70 @@ -3207,26 +3447,51 @@
- + + + + + + 10 + + + 20 + + + 40 + + + 10 + + + + + 30 + + + 40 + + + 20 + + 10 - - 20 - - - 30 - - - 40 - - - 50 - - + + + + + 60 - - - 70 + + + 70 + + + 10 + + + 20 80 @@ -3888,30 +4153,55 @@
- + + + + + + 10 + + + 20 + + + 10 + + + + + 30 + + + 50 + + + 80 + + + 20 + + 10 - + + + + + + 60 + + + 70 + + + 80 + + + 10 + + 20 - - 30 - - - 40 - - - 50 - - - 60 - - - 70 - - - 80 - 90 @@ -3928,6 +4218,12 @@ 30 + + 40 + + + 50 + @@ -4035,36 +4331,61 @@
- + + + + + + 10 + + + 20 + + + 10 + + + 20 + + + 30 + + + 50 + + + 65 + + + 90 + + + + 10 - + + + + + + 70 + + + 80 + + + 90 + + + 10 + + 20 - - 30 - - - 40 - - - 50 - - - 60 - - - 65 - - - 70 - - + 80 - - 90 - 100 @@ -4186,36 +4507,61 @@
- + + + + + + 10 + + + 20 + + + 10 + + + + + 30 + + + 50 + + + 65 + + + 90 + + + 20 + + 10 - + + + + + + 70 + + + 80 + + + 90 + + + 10 + + 20 - - 30 - - - 40 - - - 50 - - - 60 - - - 65 - - - 70 - - + 80 - - 90 - 100 @@ -4415,6 +4761,11 @@ osfamily_id name + + OSPatch + osversion_id + in_place + @@ -4426,6 +4777,9 @@ 20 + + 30 +
@@ -4461,6 +4815,9 @@ + + logo + @@ -4470,7 +4827,20 @@ - + + + + OSVersion + osfamily_id + in_place + +
@@ -4478,6 +4848,12 @@ 10 + + + 30 +
@@ -4492,6 +4868,9 @@ 10 +
@@ -4546,6 +4925,16 @@ 0 + + Model + brand_id + in_place + + + IOSVersion + brand_id + in_place + @@ -4557,9 +4946,15 @@ - + 30 + + 40 + + + 50 +
@@ -4574,6 +4969,9 @@ 10 + @@ -4874,6 +5272,11 @@ brand_id name + + NetworkDevice + iosversion_id + add_only + @@ -4885,6 +5288,9 @@ 20 + + 30 +
@@ -6189,36 +6595,61 @@
- + + + + + + 10 + + + 20 + + + 10 + + + + + 20 + + + 30 + + + 50 + + + 60 + + + 80 + + + 90 + + + 100 + + + 20 + + 10 - + + + + + + 60 + + + 10 + + 20 - - 30 - - - 40 - - - 50 - - - 60 - - - 70 - - - 80 - - - 90 - - - 100 - 110 @@ -6992,23 +7423,48 @@
- + + + + + + 10 + + + 20 + + + 30 + + + 10 + + + + + 40 + + + 60 + + + 20 + + 10 - - 20 - - - 30 - - - 40 - - + + + + + 50 - - - 60 + + + 10 + + + 20 70 @@ -7026,6 +7482,9 @@ 30 + + 40 + diff --git a/datamodels/2.x/itop-config-mgmt/dictionaries/cs.dict.itop-config-mgmt.php b/datamodels/2.x/itop-config-mgmt/dictionaries/cs.dict.itop-config-mgmt.php index 902afc29a..1bb28bf76 100644 --- a/datamodels/2.x/itop-config-mgmt/dictionaries/cs.dict.itop-config-mgmt.php +++ b/datamodels/2.x/itop-config-mgmt/dictionaries/cs.dict.itop-config-mgmt.php @@ -1528,6 +1528,12 @@ Dict::Add('CS CZ', 'Czech', 'Čeština', [ // Add translation for Fieldsets Dict::Add('CS CZ', 'Czech', 'Čeština', [ + 'ConfigMgmt:baseinfo' => 'General~~', + 'ConfigMgmt:moreinfo' => 'CI specifics~~', + 'Storage:moreinfo' => 'Storage specifics~~', + 'ConfigMgmt:otherinfo' => 'Dates and description~~', + 'Software:moreinfo' => 'Software specifics~~', + 'Phone:moreinfo' => 'Phone specifics~~', 'Server:baseinfo' => 'Obecné informace', 'Server:Date' => 'Data', 'Server:moreinfo' => 'Více informací', diff --git a/datamodels/2.x/itop-config-mgmt/dictionaries/da.dict.itop-config-mgmt.php b/datamodels/2.x/itop-config-mgmt/dictionaries/da.dict.itop-config-mgmt.php index 888320caa..43ee573ac 100644 --- a/datamodels/2.x/itop-config-mgmt/dictionaries/da.dict.itop-config-mgmt.php +++ b/datamodels/2.x/itop-config-mgmt/dictionaries/da.dict.itop-config-mgmt.php @@ -1527,6 +1527,12 @@ Dict::Add('DA DA', 'Danish', 'Dansk', [ // Add translation for Fieldsets Dict::Add('DA DA', 'Danish', 'Dansk', [ + 'ConfigMgmt:baseinfo' => 'General~~', + 'ConfigMgmt:moreinfo' => 'CI specifics~~', + 'Storage:moreinfo' => 'Storage specifics~~', + 'ConfigMgmt:otherinfo' => 'Dates and description~~', + 'Software:moreinfo' => 'Software specifics~~', + 'Phone:moreinfo' => 'Phone specifics~~', 'Server:baseinfo' => 'Almindelig Informationen', 'Server:Date' => 'Dato', 'Server:moreinfo' => 'Yderligere Information', diff --git a/datamodels/2.x/itop-config-mgmt/dictionaries/de.dict.itop-config-mgmt.php b/datamodels/2.x/itop-config-mgmt/dictionaries/de.dict.itop-config-mgmt.php index 4f930e8aa..b5e35c0bd 100644 --- a/datamodels/2.x/itop-config-mgmt/dictionaries/de.dict.itop-config-mgmt.php +++ b/datamodels/2.x/itop-config-mgmt/dictionaries/de.dict.itop-config-mgmt.php @@ -1527,6 +1527,12 @@ Dict::Add('DE DE', 'German', 'Deutsch', [ // Add translation for Fieldsets Dict::Add('DE DE', 'German', 'Deutsch', [ + 'ConfigMgmt:baseinfo' => 'General~~', + 'ConfigMgmt:moreinfo' => 'CI specifics~~', + 'Storage:moreinfo' => 'Storage specifics~~', + 'ConfigMgmt:otherinfo' => 'Dates and description~~', + 'Software:moreinfo' => 'Software specifics~~', + 'Phone:moreinfo' => 'Phone specifics~~', 'Server:baseinfo' => 'Allgemeine Informationen', 'Server:Date' => 'Datum', 'Server:moreinfo' => 'Weitere Informationen', diff --git a/datamodels/2.x/itop-config-mgmt/dictionaries/en.dict.itop-config-mgmt.php b/datamodels/2.x/itop-config-mgmt/dictionaries/en.dict.itop-config-mgmt.php index 70843b1f2..fe77073ca 100644 --- a/datamodels/2.x/itop-config-mgmt/dictionaries/en.dict.itop-config-mgmt.php +++ b/datamodels/2.x/itop-config-mgmt/dictionaries/en.dict.itop-config-mgmt.php @@ -57,26 +57,7 @@ Dict::Add('EN US', 'English', 'English', [ ////////////////////////////////////////////////////////////////////// // Classes in 'bizmodel' ////////////////////////////////////////////////////////////////////// -// -// Dictionnay conventions -// Class: -// Class:+ -// Class:/Attribute: -// Class:/Attribute:+ -// Class:/Attribute:/Value: -// Class:/Attribute:/Value:+ -// Class:/Stimulus: -// Class:/Stimulus:+ -// Class:/UniquenessRule: -// Class:/UniquenessRule:+ - -////////////////////////////////////////////////////////////////////// -// Note: The classes have been grouped by categories: bizmodel -////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////// -// Classes in 'bizmodel' -////////////////////////////////////////////////////////////////////// // // @@ -1073,6 +1054,8 @@ Dict::Add('EN US', 'English', 'English', [ 'Class:OSVersion/Attribute:osfamily_id+' => '', 'Class:OSVersion/Attribute:osfamily_name' => 'OS family name', 'Class:OSVersion/Attribute:osfamily_name+' => '', + 'Class:OSVersion/Attribute:ospatches_list' => 'OS patches', + 'Class:OSVersion/Attribute:ospatches_list+' => 'All the OS patches for this OS version', ]); // @@ -1082,6 +1065,8 @@ Dict::Add('EN US', 'English', 'English', [ Dict::Add('EN US', 'English', 'English', [ 'Class:OSFamily' => 'OS Family', 'Class:OSFamily+' => '', + 'Class:OSFamily/Attribute:osversions_list' => 'OS versions', + 'Class:OSFamily/Attribute:osversions_list+' => 'All the OS versions for this OS family', ]); // @@ -1091,8 +1076,12 @@ Dict::Add('EN US', 'English', 'English', [ Dict::Add('EN US', 'English', 'English', [ 'Class:Brand' => 'Brand', 'Class:Brand+' => '', + 'Class:Brand/Attribute:iosversions_list' => 'IOS versions', + 'Class:Brand/Attribute:iosversions_list+' => 'All the IOS versions from this brand', 'Class:Brand/Attribute:logo' => 'Logo', 'Class:Brand/Attribute:logo+' => '', + 'Class:Brand/Attribute:models_list' => 'Models', + 'Class:Brand/Attribute:models_list+' => 'All models for this brand', 'Class:Brand/Attribute:physicaldevices_list' => 'Physical devices', 'Class:Brand/Attribute:physicaldevices_list+' => 'All the physical devices corresponding to this brand', 'Class:Brand/UniquenessRule:name+' => 'The name must be unique', @@ -1104,7 +1093,7 @@ Dict::Add('EN US', 'English', 'English', [ // Dict::Add('EN US', 'English', 'English', [ - 'Class:Model' => 'Model', + 'Class:Model' => 'Device Model', 'Class:Model+' => '', 'Class:Model/ComplementaryName' => '%1$s - %2$s', 'Class:Model/Attribute:brand_id' => 'Brand', @@ -1179,6 +1168,8 @@ Dict::Add('EN US', 'English', 'English', [ 'Class:IOSVersion/Attribute:brand_id+' => '', 'Class:IOSVersion/Attribute:brand_name' => 'Brand name', 'Class:IOSVersion/Attribute:brand_name+' => '', + 'Class:IOSVersion/Attribute:networkdevices_list' => 'Network devices', + 'Class:IOSVersion/Attribute:networkdevices_list+' => 'All the network devices running this IOS version', ]); // @@ -1525,6 +1516,17 @@ Dict::Add('EN US', 'English', 'English', [ 'Class:Group/Attribute:parent_id_friendlyname+' => '', ]); +// +// Class: PhysicalInterface +// + +Dict::Add('EN US', 'English', 'English', [ + 'Class:PhysicalInterface/Attribute:org_id' => 'Org id', + 'Class:PhysicalInterface/Attribute:org_id+' => '', + 'Class:PhysicalInterface/Attribute:location_id' => 'Location id', + 'Class:PhysicalInterface/Attribute:location_id+' => '', +]); + // // Class: lnkGroupToCI // @@ -1545,23 +1547,6 @@ Dict::Add('EN US', 'English', 'English', [ 'Class:lnkGroupToCI/Attribute:reason+' => '', ]); -// Add translation for Fieldsets - -Dict::Add('EN US', 'English', 'English', [ - 'Server:baseinfo' => 'General information', - 'Server:Date' => 'Dates', - 'Server:moreinfo' => 'More information', - 'Server:otherinfo' => 'Other information', - 'Server:power' => 'Power supply', - 'Class:Subnet/Tab:IPUsage' => 'IP Usage', - 'Class:Subnet/Tab:IPUsage+' => 'Which IP within this Subnet is used or not', - 'Class:Subnet/Tab:IPUsage-explain' => 'Interfaces having an IP in the range: %1$s to %2$s', - 'Class:Subnet/Tab:FreeIPs' => 'Free IPs', - 'Class:Subnet/Tab:FreeIPs-count' => 'Free IPs: %1$s', - 'Class:Subnet/Tab:FreeIPs-explain' => 'Here is an extract of 10 free IP addresses', - 'Class:Document:PreviewTab' => 'Preview', -]); - // // Class: lnkDocumentToFunctionalCI // @@ -1580,6 +1565,29 @@ Dict::Add('EN US', 'English', 'English', [ 'Class:lnkDocumentToFunctionalCI/Attribute:document_name+' => '', ]); +// Add translation for Fieldsets + +Dict::Add('EN US', 'English', 'English', [ + 'ConfigMgmt:baseinfo' => 'General', + 'ConfigMgmt:moreinfo' => 'CI specifics', + 'ConfigMgmt:otherinfo' => 'Dates and description', + 'Storage:moreinfo' => 'Storage specifics', + 'Software:moreinfo' => 'Software specifics', + 'Phone:moreinfo' => 'Phone specifics', + 'Server:baseinfo' => 'General', + 'Server:moreinfo' => 'Device specifics', + 'Server:Date' => 'Dates', + 'Server:otherinfo' => 'Description', + 'Server:power' => 'Power supply', + 'Class:Subnet/Tab:IPUsage' => 'IP Usage', + 'Class:Subnet/Tab:IPUsage+' => 'Which IP within this Subnet is used or not', + 'Class:Subnet/Tab:IPUsage-explain' => 'Interfaces having an IP in the range: %1$s to %2$s', + 'Class:Subnet/Tab:FreeIPs' => 'Free IPs', + 'Class:Subnet/Tab:FreeIPs-count' => 'Free IPs: %1$s', + 'Class:Subnet/Tab:FreeIPs-explain' => 'Here is an extract of 10 free IP addresses', + 'Class:Document:PreviewTab' => 'Preview', +]); + // // Application Menu // @@ -1630,14 +1638,3 @@ Dict::Add('EN US', 'English', 'English', [ 'Menu:Software' => 'Software catalog', 'Menu:Software+' => 'Software catalog', ]); - -// -// Class: PhysicalInterface -// - -Dict::Add('EN US', 'English', 'English', [ - 'Class:PhysicalInterface/Attribute:org_id' => 'Org id', - 'Class:PhysicalInterface/Attribute:org_id+' => '', - 'Class:PhysicalInterface/Attribute:location_id' => 'Location id', - 'Class:PhysicalInterface/Attribute:location_id+' => '', -]); diff --git a/datamodels/2.x/itop-config-mgmt/dictionaries/en_gb.dict.itop-config-mgmt.php b/datamodels/2.x/itop-config-mgmt/dictionaries/en_gb.dict.itop-config-mgmt.php index 3f3e74dd4..bdd65aa4c 100644 --- a/datamodels/2.x/itop-config-mgmt/dictionaries/en_gb.dict.itop-config-mgmt.php +++ b/datamodels/2.x/itop-config-mgmt/dictionaries/en_gb.dict.itop-config-mgmt.php @@ -59,26 +59,6 @@ Dict::Add('EN GB', 'British English', 'British English', [ ////////////////////////////////////////////////////////////////////// // -// Dictionnay conventions -// Class: -// Class:+ -// Class:/Attribute: -// Class:/Attribute:+ -// Class:/Attribute:/Value: -// Class:/Attribute:/Value:+ -// Class:/Stimulus: -// Class:/Stimulus:+ -// Class:/UniquenessRule: -// Class:/UniquenessRule:+ - -////////////////////////////////////////////////////////////////////// -// Note: The classes have been grouped by categories: bizmodel -////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////// -// Classes in 'bizmodel' -////////////////////////////////////////////////////////////////////// -// - // // Class: lnkContactToFunctionalCI // @@ -1548,10 +1528,16 @@ Dict::Add('EN GB', 'British English', 'British English', [ // Add translation for Fieldsets Dict::Add('EN GB', 'British English', 'British English', [ - 'Server:baseinfo' => 'General information', + 'ConfigMgmt:baseinfo' => 'General', + 'ConfigMgmt:moreinfo' => 'CI specifics', + 'ConfigMgmt:otherinfo' => 'Dates and description', + 'Storage:moreinfo' => 'Storage specifics', + 'Software:moreinfo' => 'Software specifics~~', + 'Phone:moreinfo' => 'Phone specifics~~', + 'Server:baseinfo' => 'General', + 'Server:moreinfo' => 'Device specifics', 'Server:Date' => 'Dates', - 'Server:moreinfo' => 'More information', - 'Server:otherinfo' => 'Other information', + 'Server:otherinfo' => 'Description', 'Server:power' => 'Power supply', 'Class:Subnet/Tab:IPUsage' => 'IP Usage', 'Class:Subnet/Tab:IPUsage+' => 'Which IP within this Subnet is used or not', diff --git a/datamodels/2.x/itop-config-mgmt/dictionaries/es_cr.dict.itop-config-mgmt.php b/datamodels/2.x/itop-config-mgmt/dictionaries/es_cr.dict.itop-config-mgmt.php index a9690d96b..c3e6e47b8 100644 --- a/datamodels/2.x/itop-config-mgmt/dictionaries/es_cr.dict.itop-config-mgmt.php +++ b/datamodels/2.x/itop-config-mgmt/dictionaries/es_cr.dict.itop-config-mgmt.php @@ -1524,6 +1524,12 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', [ // Add translation for Fieldsets Dict::Add('ES CR', 'Spanish', 'Español, Castellano', [ + 'ConfigMgmt:baseinfo' => 'General~~', + 'ConfigMgmt:moreinfo' => 'CI specifics~~', + 'Storage:moreinfo' => 'Storage specifics~~', + 'ConfigMgmt:otherinfo' => 'Dates and description~~', + 'Software:moreinfo' => 'Software specifics~~', + 'Phone:moreinfo' => 'Phone specifics~~', 'Server:baseinfo' => 'Información General', 'Server:Date' => 'Fecha', 'Server:moreinfo' => 'Más Información', diff --git a/datamodels/2.x/itop-config-mgmt/dictionaries/fr.dict.itop-config-mgmt.php b/datamodels/2.x/itop-config-mgmt/dictionaries/fr.dict.itop-config-mgmt.php index a300007a2..8f8310bdb 100644 --- a/datamodels/2.x/itop-config-mgmt/dictionaries/fr.dict.itop-config-mgmt.php +++ b/datamodels/2.x/itop-config-mgmt/dictionaries/fr.dict.itop-config-mgmt.php @@ -36,23 +36,6 @@ Dict::Add('FR FR', 'French', 'Français', [ // Class:/UniquenessRule: // Class:/UniquenessRule:+ -////////////////////////////////////////////////////////////////////// -// Classes in 'bizmodel' -////////////////////////////////////////////////////////////////////// -// - -// Dictionnay conventions -// Class: -// Class:+ -// Class:/Attribute: -// Class:/Attribute:+ -// Class:/Attribute:/Value: -// Class:/Attribute:/Value:+ -// Class:/Stimulus: -// Class:/Stimulus:+ -// Class:/UniquenessRule: -// Class:/UniquenessRule:+ - ////////////////////////////////////////////////////////////////////// // Note: The classes have been grouped by categories: bizmodel ////////////////////////////////////////////////////////////////////// @@ -1203,6 +1186,8 @@ Dict::Add('FR FR', 'French', 'Français', [ 'Class:OSVersion/Attribute:osfamily_id+' => '', 'Class:OSVersion/Attribute:osfamily_name' => 'Nom Famille OS', 'Class:OSVersion/Attribute:osfamily_name+' => '', + 'Class:OSVersion/Attribute:ospatches_list' => 'Patchs OS', + 'Class:OSVersion/Attribute:ospatches_list+' => 'Tous les patchs de cette version OS', ]); // @@ -1212,6 +1197,8 @@ Dict::Add('FR FR', 'French', 'Français', [ Dict::Add('FR FR', 'French', 'Français', [ 'Class:OSFamily' => 'Famille OS', 'Class:OSFamily+' => '', + 'Class:OSFamily/Attribute:osversions_list' => 'Versions OS', + 'Class:OSFamily/Attribute:osversions_list+' => 'Toutes les versions OS pour cette famille', ]); // @@ -1221,8 +1208,12 @@ Dict::Add('FR FR', 'French', 'Français', [ Dict::Add('FR FR', 'French', 'Français', [ 'Class:Brand' => 'Marque', 'Class:Brand+' => '', + 'Class:Brand/Attribute:iosversions_list' => 'Versions IOS', + 'Class:Brand/Attribute:iosversions_list+' => 'Toutes les versions IOS pour cette marque', 'Class:Brand/Attribute:logo' => 'Logo', 'Class:Brand/Attribute:logo+' => '', + 'Class:Brand/Attribute:models_list' => 'Modèles', + 'Class:Brand/Attribute:models_list+' => 'Tous les modèles pour cette marque', 'Class:Brand/Attribute:physicaldevices_list' => 'Matériels', 'Class:Brand/Attribute:physicaldevices_list+' => 'Tous les matériels correspondant à cette marque', 'Class:Brand/Attribute:physicaldevices_list/UI:Links:Create:Button+' => 'Créer un %4$s', @@ -1240,7 +1231,7 @@ Dict::Add('FR FR', 'French', 'Français', [ // Dict::Add('FR FR', 'French', 'Français', [ - 'Class:Model' => 'Modèle', + 'Class:Model' => 'Modèle de matériel', 'Class:Model+' => '', 'Class:Model/ComplementaryName' => '%1$s - %2$s', 'Class:Model/Attribute:brand_id' => 'Marque', @@ -1327,6 +1318,8 @@ Dict::Add('FR FR', 'French', 'Français', [ 'Class:IOSVersion/Attribute:brand_id+' => '', 'Class:IOSVersion/Attribute:brand_name' => 'Nom Marque', 'Class:IOSVersion/Attribute:brand_name+' => '', + 'Class:IOSVersion/Attribute:networkdevices_list' => 'Equipements réseaux', + 'Class:IOSVersion/Attribute:networkdevices_list+' => 'Tous les équipements réseaux utilisant cette version IOS', ]); // @@ -1675,6 +1668,17 @@ Dict::Add('FR FR', 'French', 'Français', [ 'Class:Group/Attribute:parent_id_friendlyname+' => '', ]); +// +// Class: PhysicalInterface +// + +Dict::Add('FR FR', 'French', 'Français', [ + 'Class:PhysicalInterface/Attribute:org_id' => 'Organisation', + 'Class:PhysicalInterface/Attribute:org_id+' => '', + 'Class:PhysicalInterface/Attribute:location_id' => 'Site', + 'Class:PhysicalInterface/Attribute:location_id+' => '', +]); + // // Class: lnkGroupToCI // @@ -1695,23 +1699,6 @@ Dict::Add('FR FR', 'French', 'Français', [ 'Class:lnkGroupToCI/Attribute:reason+' => '', ]); -// Add translation for Fieldsets - -Dict::Add('FR FR', 'French', 'Français', [ - 'Server:baseinfo' => 'Informations générales', - 'Server:Date' => 'Dates', - 'Server:moreinfo' => 'Informations complémentaires', - 'Server:otherinfo' => 'Autres informations', - 'Server:power' => 'Alimentation électrique', - 'Class:Subnet/Tab:IPUsage' => 'IP utilisées', - 'Class:Subnet/Tab:IPUsage+' => 'Utilisation des IPs de ce subnet', - 'Class:Subnet/Tab:IPUsage-explain' => 'Interfaces ayant une IP dans la plage: %1$s à %2$s', - 'Class:Subnet/Tab:FreeIPs' => 'IP disponibles', - 'Class:Subnet/Tab:FreeIPs-count' => 'IP disponibles: %1$s', - 'Class:Subnet/Tab:FreeIPs-explain' => 'Voici un échantillon de dix addresses IP disponibles', - 'Class:Document:PreviewTab' => 'Aperçu', -]); - // // Class: lnkDocumentToFunctionalCI // @@ -1730,6 +1717,29 @@ Dict::Add('FR FR', 'French', 'Français', [ 'Class:lnkDocumentToFunctionalCI/Attribute:document_name+' => '', ]); +// Add translation for Fieldsets + +Dict::Add('FR FR', 'French', 'Français', [ + 'ConfigMgmt:baseinfo' => 'Informations générales', + 'Server:baseinfo' => 'Informations générales', + 'ConfigMgmt:moreinfo' => 'Item spécifique', + 'Server:moreinfo' => 'Matériel spécifique', + 'Storage:moreinfo' => 'Stockage spécifique', + 'Software:moreinfo' => 'Logiciel spécifique', + 'Phone:moreinfo' => 'Téléphone spécifique', + 'ConfigMgmt:otherinfo' => 'Dates et description', + 'Server:Date' => 'Dates', + 'Server:otherinfo' => 'Description', + 'Server:power' => 'Alimentation électrique', + 'Class:Subnet/Tab:IPUsage' => 'IP utilisées', + 'Class:Subnet/Tab:IPUsage+' => 'Utilisation des IPs de ce subnet', + 'Class:Subnet/Tab:IPUsage-explain' => 'Interfaces ayant une IP dans la plage: %1$s à %2$s', + 'Class:Subnet/Tab:FreeIPs' => 'IP disponibles', + 'Class:Subnet/Tab:FreeIPs-count' => 'IP disponibles: %1$s', + 'Class:Subnet/Tab:FreeIPs-explain' => 'Voici un échantillon de dix addresses IP disponibles', + 'Class:Document:PreviewTab' => 'Aperçu', +]); + // // Application Menu // @@ -1780,14 +1790,3 @@ Dict::Add('FR FR', 'French', 'Français', [ 'Menu:Software' => 'Catalogue des logiciels de références', 'Menu:Software+' => 'Catalogue des logiciels de références', ]); - -// -// Class: PhysicalInterface -// - -Dict::Add('FR FR', 'French', 'Français', [ - 'Class:PhysicalInterface/Attribute:org_id' => 'Organisation', - 'Class:PhysicalInterface/Attribute:org_id+' => '', - 'Class:PhysicalInterface/Attribute:location_id' => 'Site', - 'Class:PhysicalInterface/Attribute:location_id+' => '', -]); diff --git a/datamodels/2.x/itop-config-mgmt/dictionaries/hu.dict.itop-config-mgmt.php b/datamodels/2.x/itop-config-mgmt/dictionaries/hu.dict.itop-config-mgmt.php index 9dae7cbc6..181e114d7 100644 --- a/datamodels/2.x/itop-config-mgmt/dictionaries/hu.dict.itop-config-mgmt.php +++ b/datamodels/2.x/itop-config-mgmt/dictionaries/hu.dict.itop-config-mgmt.php @@ -1526,10 +1526,16 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', [ // Add translation for Fieldsets Dict::Add('HU HU', 'Hungarian', 'Magyar', [ + 'ConfigMgmt:baseinfo' => 'General~~', + 'ConfigMgmt:moreinfo' => 'CI specifics~~', + 'Storage:moreinfo' => 'Storage specifics~~', + 'ConfigMgmt:otherinfo' => 'Dates and description~~', + 'Software:moreinfo' => 'Software specifics~~', + 'Phone:moreinfo' => 'Phone specifics~~', 'Server:baseinfo' => 'Általános információ', 'Server:Date' => 'Dátumok', 'Server:moreinfo' => 'További információ', - 'Server:otherinfo' => 'Other information~~', + 'Server:otherinfo' => 'Description~~', 'Server:power' => 'Áramforrás', 'Class:Subnet/Tab:IPUsage' => 'IP felhasználás', 'Class:Subnet/Tab:IPUsage+' => 'Which IP within this Subnet is used or not~~', diff --git a/datamodels/2.x/itop-config-mgmt/dictionaries/it.dict.itop-config-mgmt.php b/datamodels/2.x/itop-config-mgmt/dictionaries/it.dict.itop-config-mgmt.php index b691acb80..5d25bc989 100644 --- a/datamodels/2.x/itop-config-mgmt/dictionaries/it.dict.itop-config-mgmt.php +++ b/datamodels/2.x/itop-config-mgmt/dictionaries/it.dict.itop-config-mgmt.php @@ -1547,6 +1547,12 @@ Dict::Add('IT IT', 'Italian', 'Italiano', [ // Add translation for Fieldsets Dict::Add('IT IT', 'Italian', 'Italiano', [ + 'ConfigMgmt:baseinfo' => 'General~~', + 'ConfigMgmt:moreinfo' => 'CI specifics~~', + 'Storage:moreinfo' => 'Storage specifics~~', + 'ConfigMgmt:otherinfo' => 'Dates and description~~', + 'Software:moreinfo' => 'Software specifics~~', + 'Phone:moreinfo' => 'Phone specifics~~', 'Server:baseinfo' => 'Informazioni generali', 'Server:Date' => 'Date', 'Server:moreinfo' => 'Ulteriori informazioni', diff --git a/datamodels/2.x/itop-config-mgmt/dictionaries/ja.dict.itop-config-mgmt.php b/datamodels/2.x/itop-config-mgmt/dictionaries/ja.dict.itop-config-mgmt.php index 1851ae423..407310cda 100644 --- a/datamodels/2.x/itop-config-mgmt/dictionaries/ja.dict.itop-config-mgmt.php +++ b/datamodels/2.x/itop-config-mgmt/dictionaries/ja.dict.itop-config-mgmt.php @@ -1526,6 +1526,12 @@ Dict::Add('JA JP', 'Japanese', '日本語', [ // Add translation for Fieldsets Dict::Add('JA JP', 'Japanese', '日本語', [ + 'ConfigMgmt:baseinfo' => 'General~~', + 'ConfigMgmt:moreinfo' => 'CI specifics~~', + 'Storage:moreinfo' => 'Storage specifics~~', + 'ConfigMgmt:otherinfo' => 'Dates and description~~', + 'Software:moreinfo' => 'Software specifics~~', + 'Phone:moreinfo' => 'Phone specifics~~', 'Server:baseinfo' => '基本情報', 'Server:Date' => '日付', 'Server:moreinfo' => '追加情報', diff --git a/datamodels/2.x/itop-config-mgmt/dictionaries/nl.dict.itop-config-mgmt.php b/datamodels/2.x/itop-config-mgmt/dictionaries/nl.dict.itop-config-mgmt.php index 487f54498..52c7df5e4 100644 --- a/datamodels/2.x/itop-config-mgmt/dictionaries/nl.dict.itop-config-mgmt.php +++ b/datamodels/2.x/itop-config-mgmt/dictionaries/nl.dict.itop-config-mgmt.php @@ -1528,6 +1528,12 @@ Dict::Add('NL NL', 'Dutch', 'Nederlands', [ // Add translation for Fieldsets Dict::Add('NL NL', 'Dutch', 'Nederlands', [ + 'ConfigMgmt:baseinfo' => 'General~~', + 'ConfigMgmt:moreinfo' => 'CI specifics~~', + 'Storage:moreinfo' => 'Storage specifics~~', + 'ConfigMgmt:otherinfo' => 'Dates and description~~', + 'Software:moreinfo' => 'Software specifics~~', + 'Phone:moreinfo' => 'Phone specifics~~', 'Server:baseinfo' => 'Globale informatie', 'Server:Date' => 'Datum', 'Server:moreinfo' => 'Meer informatie', diff --git a/datamodels/2.x/itop-config-mgmt/dictionaries/pl.dict.itop-config-mgmt.php b/datamodels/2.x/itop-config-mgmt/dictionaries/pl.dict.itop-config-mgmt.php index 84bd23043..9844ca33a 100644 --- a/datamodels/2.x/itop-config-mgmt/dictionaries/pl.dict.itop-config-mgmt.php +++ b/datamodels/2.x/itop-config-mgmt/dictionaries/pl.dict.itop-config-mgmt.php @@ -1526,6 +1526,12 @@ Dict::Add('PL PL', 'Polish', 'Polski', [ // Add translation for Fieldsets Dict::Add('PL PL', 'Polish', 'Polski', [ + 'ConfigMgmt:baseinfo' => 'General~~', + 'ConfigMgmt:moreinfo' => 'CI specifics~~', + 'Storage:moreinfo' => 'Storage specifics~~', + 'ConfigMgmt:otherinfo' => 'Dates and description~~', + 'Software:moreinfo' => 'Software specifics~~', + 'Phone:moreinfo' => 'Phone specifics~~', 'Server:baseinfo' => 'Informacje ogólne', 'Server:Date' => 'Daty', 'Server:moreinfo' => 'Więcej informacji', diff --git a/datamodels/2.x/itop-config-mgmt/dictionaries/pt_br.dict.itop-config-mgmt.php b/datamodels/2.x/itop-config-mgmt/dictionaries/pt_br.dict.itop-config-mgmt.php index cbb232a58..7bade5c06 100644 --- a/datamodels/2.x/itop-config-mgmt/dictionaries/pt_br.dict.itop-config-mgmt.php +++ b/datamodels/2.x/itop-config-mgmt/dictionaries/pt_br.dict.itop-config-mgmt.php @@ -1526,6 +1526,12 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', [ // Add translation for Fieldsets Dict::Add('PT BR', 'Brazilian', 'Brazilian', [ + 'ConfigMgmt:baseinfo' => 'General~~', + 'ConfigMgmt:moreinfo' => 'CI specifics~~', + 'Storage:moreinfo' => 'Storage specifics~~', + 'ConfigMgmt:otherinfo' => 'Dates and description~~', + 'Software:moreinfo' => 'Software specifics~~', + 'Phone:moreinfo' => 'Phone specifics~~', 'Server:baseinfo' => 'Informações gerais', 'Server:Date' => 'Data', 'Server:moreinfo' => 'Mais informações', diff --git a/datamodels/2.x/itop-config-mgmt/dictionaries/ru.dict.itop-config-mgmt.php b/datamodels/2.x/itop-config-mgmt/dictionaries/ru.dict.itop-config-mgmt.php index 861fd5db7..01ecdad6d 100644 --- a/datamodels/2.x/itop-config-mgmt/dictionaries/ru.dict.itop-config-mgmt.php +++ b/datamodels/2.x/itop-config-mgmt/dictionaries/ru.dict.itop-config-mgmt.php @@ -1527,6 +1527,12 @@ Dict::Add('RU RU', 'Russian', 'Русский', [ // Add translation for Fieldsets Dict::Add('RU RU', 'Russian', 'Русский', [ + 'ConfigMgmt:baseinfo' => 'General~~', + 'ConfigMgmt:moreinfo' => 'CI specifics~~', + 'Storage:moreinfo' => 'Storage specifics~~', + 'ConfigMgmt:otherinfo' => 'Dates and description~~', + 'Software:moreinfo' => 'Software specifics~~', + 'Phone:moreinfo' => 'Phone specifics~~', 'Server:baseinfo' => 'Основное', 'Server:Date' => 'Даты', 'Server:moreinfo' => 'Спецификация', diff --git a/datamodels/2.x/itop-config-mgmt/dictionaries/sk.dict.itop-config-mgmt.php b/datamodels/2.x/itop-config-mgmt/dictionaries/sk.dict.itop-config-mgmt.php index d1d80a81a..d1319feda 100644 --- a/datamodels/2.x/itop-config-mgmt/dictionaries/sk.dict.itop-config-mgmt.php +++ b/datamodels/2.x/itop-config-mgmt/dictionaries/sk.dict.itop-config-mgmt.php @@ -1526,6 +1526,12 @@ Dict::Add('SK SK', 'Slovak', 'Slovenčina', [ // Add translation for Fieldsets Dict::Add('SK SK', 'Slovak', 'Slovenčina', [ + 'ConfigMgmt:baseinfo' => 'General~~', + 'ConfigMgmt:moreinfo' => 'CI specifics~~', + 'Storage:moreinfo' => 'Storage specifics~~', + 'ConfigMgmt:otherinfo' => 'Dates and description~~', + 'Software:moreinfo' => 'Software specifics~~', + 'Phone:moreinfo' => 'Phone specifics~~', 'Server:baseinfo' => 'Všeobecné informácie', 'Server:Date' => 'Dátum', 'Server:moreinfo' => 'Viac informácií', diff --git a/datamodels/2.x/itop-config-mgmt/dictionaries/tr.dict.itop-config-mgmt.php b/datamodels/2.x/itop-config-mgmt/dictionaries/tr.dict.itop-config-mgmt.php index ad2b07d0c..3ea5fcd62 100644 --- a/datamodels/2.x/itop-config-mgmt/dictionaries/tr.dict.itop-config-mgmt.php +++ b/datamodels/2.x/itop-config-mgmt/dictionaries/tr.dict.itop-config-mgmt.php @@ -1527,6 +1527,12 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', [ // Add translation for Fieldsets Dict::Add('TR TR', 'Turkish', 'Türkçe', [ + 'ConfigMgmt:baseinfo' => 'General~~', + 'ConfigMgmt:moreinfo' => 'CI specifics~~', + 'Storage:moreinfo' => 'Storage specifics~~', + 'ConfigMgmt:otherinfo' => 'Dates and description~~', + 'Software:moreinfo' => 'Software specifics~~', + 'Phone:moreinfo' => 'Phone specifics~~', 'Server:baseinfo' => 'Genel Bilgi', 'Server:Date' => 'Tarihler', 'Server:moreinfo' => 'Daha fazla bilgi', diff --git a/datamodels/2.x/itop-config-mgmt/dictionaries/zh_cn.dict.itop-config-mgmt.php b/datamodels/2.x/itop-config-mgmt/dictionaries/zh_cn.dict.itop-config-mgmt.php index 19702c15e..e330c6139 100644 --- a/datamodels/2.x/itop-config-mgmt/dictionaries/zh_cn.dict.itop-config-mgmt.php +++ b/datamodels/2.x/itop-config-mgmt/dictionaries/zh_cn.dict.itop-config-mgmt.php @@ -1543,6 +1543,12 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', [ // Add translation for Fieldsets Dict::Add('ZH CN', 'Chinese', '简体中文', [ + 'ConfigMgmt:baseinfo' => 'General~~', + 'ConfigMgmt:moreinfo' => 'CI specifics~~', + 'Storage:moreinfo' => 'Storage specifics~~', + 'ConfigMgmt:otherinfo' => 'Dates and description~~', + 'Software:moreinfo' => 'Software specifics~~', + 'Phone:moreinfo' => 'Phone specifics~~', 'Server:baseinfo' => '基本信息', 'Server:Date' => '日期', 'Server:moreinfo' => '更多信息', diff --git a/datamodels/2.x/itop-config/src/Controller/ConfigEditorController.php b/datamodels/2.x/itop-config/src/Controller/ConfigEditorController.php index c45c4f015..aba7d2eb8 100644 --- a/datamodels/2.x/itop-config/src/Controller/ConfigEditorController.php +++ b/datamodels/2.x/itop-config/src/Controller/ConfigEditorController.php @@ -28,6 +28,7 @@ class ConfigEditorController extends Controller public function __construct() { parent::__construct(MODULESROOT.static::MODULE_NAME.'/templates', static::MODULE_NAME); + $this->SetDebugAllowed(false); } public function OperationEdit(): void diff --git a/datamodels/2.x/itop-container-mgmt/data/en_us.data.itop-container-image-type.xml b/datamodels/2.x/itop-container-mgmt/data/en_us.data.itop-container-image-type.xml new file mode 100644 index 000000000..35d246288 --- /dev/null +++ b/datamodels/2.x/itop-container-mgmt/data/en_us.data.itop-container-image-type.xml @@ -0,0 +1,12 @@ + + + + Docker Hardened Image + + + Docker Official Image + + + Verified Publisher + + \ No newline at end of file diff --git a/datamodels/2.x/itop-container-mgmt/data/en_us.data.itop-container-type.xml b/datamodels/2.x/itop-container-mgmt/data/en_us.data.itop-container-type.xml new file mode 100644 index 000000000..96735c598 --- /dev/null +++ b/datamodels/2.x/itop-container-mgmt/data/en_us.data.itop-container-type.xml @@ -0,0 +1,27 @@ + + + + AWS - Elastic Container Service + + + AWS - Elastic Kubernetes Service + + + Azure Kubernetes Service + + + Docker Swarm + + + Google Kubernetes Engine + + + Kubernetes + + + Nomad + + + OpenShift + + \ No newline at end of file diff --git a/datamodels/2.x/itop-container-mgmt/datamodel.itop-container-mgmt.xml b/datamodels/2.x/itop-container-mgmt/datamodel.itop-container-mgmt.xml new file mode 100644 index 000000000..21f92024b --- /dev/null +++ b/datamodels/2.x/itop-container-mgmt/datamodel.itop-container-mgmt.xml @@ -0,0 +1,1280 @@ + + + + + cmdbAbstractObject + + bizmodel,searchable + false + containerimage + + + + + + + + + + + + + + + + + + + + + + + + + + + false + true + + + + + + name + + false + + + publisher + + false + + + version + + false + + + description + + true + + + containerimagetype_id + ContainerImageType + true + DEL_MANUAL + + + software_id + + + true + Software + DEL_MANUAL + all + + + image + + false + + all + + + lnkContainerApplicationToImage + containerimage_id + 0 + 0 + containerapplication_id + + + + + + + + + 10 + + + 20 + + + 30 + + + 40 + + + + + + + 10 + + + 20 + + + 30 + + + 40 + + + 50 + + + +
+ + + + + + + 10 + + + 20 + + + 10 + + + + + 10 + + + 20 + + + 30 + + + 40 + + + 10 + + + 10 + + + + + + + 60 + + + 10 + + + 20 + + + 50 + + +
+ + + + 30 + + + 40 + + + 50 + + + +
+ + + + + containerapplications_list + both + + + + +
+ + + + SELECT FunctionalCI WHERE IF(:this->finalclass = 'ContainerApplication', finalclass = 'ContainerVirtualHost', finalclass IN ('Server','VirtualMachine','PC')) + + + + + SoftwareInstance + + bizmodel,searchable + false + containerapplication + + + + + + + + + + + + + + + + + status + + + + + + descriptor + true + + + containervirtualhost_id + + false + ContainerVirtualHost + DEL_AUTO + all + + + lnkContainerApplicationToImage + containerapplication_id + 0 + 0 + containerimage_id + + + + + + false + public + EventListener + Set('system_id', $this->Get('containervirtualhost_id')); + }]]> + + + + + EVENT_DB_BEFORE_WRITE + EvtComputeSystemId + 0 + + + + + + + 10 + + + 20 + + + 30 + + + 40 + + + + + + + 10 + + + 20 + + + 30 + + + 40 + + + +
+ + + + + + + 10 + + + 20 + + + 30 + + + 40 + + + 10 + + + + + 10 + + + 10 + + + 20 + + + 10 + + + + + + + 50 + + + 60 + + + 10 + + + 20 + + + 30 + + + 40 + + + 50 + + + 60 + + + 70 + + + 80 + + +
+ + + + 10 + + + 20 + + + 30 + + + 40 + + + +
+
+ + cmdbAbstractObject + + 1 + bizmodel + false + autoincrement + lnkcontainerapplicationtoimage + id + + + + + + + + + + + + + + + + + + + + + + false + true + + + + + + containerapplication_id + ContainerApplication + false + DEL_AUTO + + + containerimage_id + ContainerImage + false + DEL_AUTO + + + + +
+ + + 10 + + + 20 + + +
+ + + + 10 + + + 20 + + + + + + + 10 + + + 20 + + + +
+
+ + FunctionalCI + + bizmodel,searchable + true + containervirtualhost + + + + + + + + + + + + + + + status + + + status='obsolete' + + + + + ContainerApplication + containervirtualhost_id + list + + false + false + + + + status + + + implementation + 10 + + + + production + 20 + + + + obsolete + 30 + + + + + $ibo-lifecycle-neutral-state-primary-color + $ibo-lifecycle-neutral-state-secondary-color + + + + implementation + false + + + all + + + containertype_id + + + true + ContainerType + DEL_MANUAL + all + + + + + + + + 10 + + + 20 + + + 30 + + + 40 + + + + + + + 10 + + + 20 + + + 30 + + + 40 + + + +
+ + + + + + + 10 + + + 20 + + + 30 + + + 40 + + + 10 + + + + + 10 + + + 20 + + + 20 + + + 10 + + + + + + + 50 + + + 60 + + + 10 + + + 20 + + + 30 + + + 40 + + + 50 + + + 60 + + +
+ + + + 10 + + + 20 + + + 30 + + + +
+ + + + + containerapplications_list + both + + + + +
+ + ContainerVirtualHost + + bizmodel,searchable + false + containerhost + + + + + + + + + + + + + + + + + + + status + + + + + + containercluster_id + SELECT ContainerCluster WHERE org_id= :this->org_id + true + ContainerCluster + DEL_MANUAL + all + + + role + + + master + 10 + + + worker + 20 + + + standalone + 30 + + + + standalone + false + radio_horizontal + + + + all + + + system_id + SELECT FunctionalCI WHERE finalclass IN ('Server','VirtualMachine','Cloud') + false + FunctionalCI + DEL_AUTO + all + + + + + /** + * Event Listener for EVENT_DB_BEFORE_WRITE + * An object is about to be written into the database. + * The object can be modified. + * + * @param Combodo\iTop\Service\Events\EventData $oEventData Event data object + * + */ + false + public + EventListener + Get('containercluster_id') == 0) { + $this->Set('role', 'standalone'); + } else if ($this->Get('role') == 'standalone') { + $this->Set('role', 'worker'); + } +}]]> + + + + + + + 10 + + + 20 + + + 30 + + + 40 + + + 50 + + + + + + + 10 + + + 20 + + + 30 + + + 40 + + + +
+ + + + + + + 10 + + + 20 + + + 30 + + + 40 + + + 10 + + + + + 10 + + + 20 + + + 30 + + + 40 + + + 20 + + + 10 + + + + + + + 50 + + + 60 + + + 10 + + + 20 + + + 30 + + + 40 + + + 50 + + + 60 + + +
+ + + + 10 + + + 20 + + + 30 + + + 40 + + + 50 + + + 60 + + + +
+ + + + + containercluster_id + both + + + + + + + EVENT_DB_BEFORE_WRITE + EvtBeforeWrite + 0 + + +
+ + ContainerVirtualHost + + bizmodel,searchable + false + containercluster + + + + + + + + + + + + + + + status + + + + + + redundancy + impacts + ContainerHost + containercluster + true + 50 + percent + user + user + + + ContainerHost + containercluster_id + list + + false + false + on_host_display + + + + + + + + 10 + + + 20 + + + 30 + + + + + + + 10 + + + 20 + + + 30 + + + 40 + + + +
+ + + + + + + 10 + + + 20 + + + 30 + + + 40 + + + 10 + + + + + 10 + + + 20 + + + 10 + + + + + + + 50 + + + 60 + + + 10 + + + 20 + + + 30 + + + 40 + + + 50 + + + 60 + + + 70 + + +
+ + + + 10 + + + 20 + + + 30 + + + 40 + + + +
+
+ + Typology + + bizmodel,searchable + false + containertype + + + + + + + + + + + + + + + + + + + 10 + + + + + + + 10 + + + +
+ + + 10 + + +
+
+
+ + Typology + + bizmodel,searchable + false + containerimagetype + + + + + + + + + + + + + + + + + + + 10 + + + + + + + 10 + + + +
+ + + 10 + + +
+
+
+ + + + ContainerHost + system_id + list + + false + false + + + + +
+ + + 40 + + +
+
+ + + + + containerhosts_list + both + + + + +
+
+ + + + + + 1 + + + 5 + ContainerApplication + + + 6 + ContainerHost + + + 7 + ContainerCluster + + + 8 + ContainerImage + + + + + + + + + + + 0 + + + 21 + ContainerType + + + 22 + ContainerImageType + + + + + + + +
diff --git a/datamodels/2.x/itop-container-mgmt/dictionaries/en.dict.itop-container-mgmt.php b/datamodels/2.x/itop-container-mgmt/dictionaries/en.dict.itop-container-mgmt.php new file mode 100644 index 000000000..cd17eb63d --- /dev/null +++ b/datamodels/2.x/itop-container-mgmt/dictionaries/en.dict.itop-container-mgmt.php @@ -0,0 +1,156 @@ + 'General', + 'Container:moreinfo' => 'Container specifics', + 'Container:otherinfo' => 'Dates and description', +]); + +// +// Class Container Image +// + +Dict::Add('EN US', 'English', 'English', [ + 'Class:ContainerImage/Name' => '%1$s %2$s', + 'Class:ContainerImage/ComplementaryName' => '%1$s - %2$s', + 'Class:ContainerImage' => 'Container Image', + 'Class:ContainerImage+' => 'The image of a software ready to be launched as a container', + 'Class:ContainerImage/Attribute:name' => 'Name', + 'Class:ContainerImage/Attribute:name+' => '', + 'Class:ContainerImage/Attribute:version' => 'Version', + 'Class:ContainerImage/Attribute:version+' => '', + 'Class:ContainerImage/Attribute:description' => 'Description', + 'Class:ContainerImage/Attribute:description+' => '', + 'Class:ContainerImage/Attribute:publisher' => 'Publisher', + 'Class:ContainerImage/Attribute:publisher+' => 'Publisher of the image. Eg. php, nginx, ...', + 'Class:ContainerImage/Attribute:image' => 'Image', + 'Class:ContainerImage/Attribute:image+' => 'Detailed information to retrieve the image on the appropriate hosting platform', + 'Class:ContainerImage/Attribute:type_id' => 'Type', + 'Class:ContainerImage/Attribute:type_id+' => 'Type d\image', + 'Class:ContainerImage/Attribute:software_id' => 'Software', + 'Class:ContainerImage/Attribute:software_id+' => '', + 'Class:ContainerImage/Attribute:containerapplications_list' => 'Containerized Applications', + 'Class:ContainerImage/Attribute:containerapplications_list+' => 'Applications to which this image contributes', +]); + +// +// Class Container Application +// + +Dict::Add('EN US', 'English', 'English', [ + 'Class:ContainerApplication/Name' => '%1$s', + 'Class:ContainerApplication/ComplementaryName' => '%1$s', + 'Class:ContainerApplication' => 'Containerized Application', + 'Class:ContainerApplication+' => 'An application deployed on a Container Platform', + 'Class:ContainerApplication/Attribute:descriptor' => 'Deployment file', + 'Class:ContainerApplication/Attribute:descriptor+' => 'File describing how to deploy the application on the container platform (e.g., Docker Compose, Helm Chart, etc.)', + 'Class:ContainerApplication/Attribute:containervirtualhost_id' => 'Container Host', + 'Class:ContainerApplication/Attribute:containervirtualhost_id+' => 'Container Platform on which the application is running', + 'Class:ContainerApplication/Attribute:containertype_id' => 'Container type', + 'Class:ContainerApplication/Attribute:containertype_id+' => 'Technology used for containerization', + 'Class:ContainerApplication/Attribute:containerimages_list' => 'Container images', + 'Class:ContainerApplication/Attribute:containerimages_list+' => 'Software images used to build the containerized application', + +]); + +// +// Class: lnkContainerApplicationToImage +// + +Dict::Add('EN US', 'English', 'English', [ + 'Class:lnkContainerApplicationToImage' => 'Link Container Application / Image', + 'Class:lnkContainerApplicationToImage+' => '', + 'Class:lnkContainerApplicationToImage/Name' => '%1$s / %2$s', + 'Class:lnkContainerApplicationToImage/Name+' => '', + 'Class:lnkContainerApplicationToImage/Attribute:containerapplication_id' => 'Containerized Application', + 'Class:lnkContainerApplicationToImage/Attribute:containerapplication_id+' => 'Application which uses this image', + 'Class:lnkContainerApplicationToImage/Attribute:containerimage_id' => 'Container Image', + 'Class:lnkContainerApplicationToImage/Attribute:containerimage_id+' => 'Software image used to build the containerized application', +]); + +// +// Class Container Virtual Host +// + +Dict::Add('EN US', 'English', 'English', [ + 'Class:ContainerVirtualHost/Name' => '%1$s', + 'Class:ContainerVirtualHost/ComplementaryName' => '', + 'Class:ContainerVirtualHost' => 'Container Platform', + 'Class:ContainerVirtualHost+' => 'Platform on which applications run as containers', + 'Class:ContainerVirtualHost/Attribute:containertype_id' => 'Container Type', + 'Class:ContainerVirtualHost/Attribute:containertype_id+' => 'Technology used to deliver containerization', + 'Class:ContainerVirtualHost/Attribute:status' => 'Status', + 'Class:ContainerVirtualHost/Attribute:status+' => 'Status of the container platform', + 'Class:ContainerVirtualHost/Attribute:containerapplications_list' => 'Applications', + 'Class:ContainerVirtualHost/Attribute:containerapplications_list+' => 'Applications running on this container environment', +]); + +// +// Class Container Host +// + +Dict::Add('EN US', 'English', 'English', [ + 'Class:ContainerHost/Name' => '%1$s', + 'Class:ContainerHost/ComplementaryName' => '%1$s-%2$s', + 'Class:ContainerHost' => 'Container Host', + 'Class:ContainerHost+' => 'Host dedicated to containers. It is the basic element of a Container Platform', + 'Class:ContainerHost/Attribute:containercluster_id' => 'Container Cluster', + 'Class:ContainerHost/Attribute:containercluster_id+' => '', + 'Class:ContainerHost/Attribute:role' => 'Role', + 'Class:ContainerHost/Attribute:role+' => 'Role of the host within its cluster: Master or Worker. Standalone when not part of a cluster.', + 'Class:ContainerHost/Attribute:system_id' => 'System', + 'Class:ContainerHost/Attribute:system_id+' => 'The system can be a Server, a Virtual Machine, a Cloud, ...', + 'Class:ContainerHost/Attribute:role/Value:master' => 'Master', + 'Class:ContainerHost/Attribute:role/Value:worker' => 'Worker', + 'Class:ContainerHost/Attribute:role/Value:standalone' => 'Standalone', +]); + +// +// Class Container Cluster +// + +Dict::Add('EN US', 'English', 'English', [ + 'Class:ContainerCluster/Name' => '%1$s', + 'Class:ContainerCluster/ComplementaryName' => '', + 'Class:ContainerCluster' => 'Container Cluster', + 'Class:ContainerCluster+' => 'A Container Platform made of a cluster of Container Hosts', + 'Class:ContainerCluster/Attribute:redundancy' => 'Configuration of the redundancy', + 'Class:ContainerCluster/Attribute:redundancy/disabled' => 'The cluster is up if all its hosts are up', + 'Class:ContainerCluster/Attribute:redundancy/count' => 'The cluster is up if at least %1$s hosts are up', + 'Class:ContainerCluster/Attribute:redundancy/percent' => 'The cluster is up if at least %1$s %% of the hosts are up', + 'Class:ContainerCluster/Attribute:containerhosts_list' => 'Container Hosts', + 'Class:ContainerCluster/Attribute:containerhosts_list+' => 'Hosts part of this cluster', +]); + +// +// Class Container Type +// + +Dict::Add('EN US', 'English', 'English', [ + 'Class:ContainerType/Name' => '%1$s', + 'Class:ContainerType/ComplementaryName' => '', + 'Class:ContainerType' => 'Container Type', + 'Class:ContainerType+' => 'Technology used to deliver containerization', +]); + +// +// Class Container Type +// + +Dict::Add('EN US', 'English', 'English', [ + 'Class:ContainerImageType/Name' => '%1$s', + 'Class:ContainerImageType/ComplementaryName' => '', + 'Class:ContainerImageType' => 'Container Image Type', + 'Class:ContainerImageType+' => 'Typology of container images', +]); diff --git a/datamodels/2.x/itop-container-mgmt/dictionaries/fr.dict.itop-container-mgmt.php b/datamodels/2.x/itop-container-mgmt/dictionaries/fr.dict.itop-container-mgmt.php new file mode 100644 index 000000000..3352216c0 --- /dev/null +++ b/datamodels/2.x/itop-container-mgmt/dictionaries/fr.dict.itop-container-mgmt.php @@ -0,0 +1,157 @@ + 'Informations générales', + 'Container:moreinfo' => 'Spécificités de la conteneurisation', + 'Container:otherinfo' => 'Dates et description', +]); + +// +// Class Container Image +// + +Dict::Add('FR FR', 'French', 'Français', [ + 'Class:ContainerImage/Name' => '%1$s %2$s', + 'Class:ContainerImage/ComplementaryName' => '%1$s - %2$s', + 'Class:ContainerImage' => 'Image pour Conteneur', + 'Class:ContainerImage+' => 'L\'image d\'un logiciel, constituant d\'une Application Conteneurisée', + 'Class:ContainerImage/Attribute:name' => 'Nom', + 'Class:ContainerImage/Attribute:name+' => '', + 'Class:ContainerImage/Attribute:version' => 'Version', + 'Class:ContainerImage/Attribute:version+' => '', + 'Class:ContainerImage/Attribute:description' => 'Description', + 'Class:ContainerImage/Attribute:description+' => '', + 'Class:ContainerImage/Attribute:publisher' => 'Editeur', + 'Class:ContainerImage/Attribute:publisher+' => 'Fournisseur de l\image', + 'Class:ContainerImage/Attribute:image' => 'Image', + 'Class:ContainerImage/Attribute:image+' => 'Détail permettant de récupérer l\'image sur la plateforme d\'hébergement appropriée', + 'Class:ContainerImage/Attribute:type_id' => 'Type', + 'Class:ContainerImage/Attribute:type_id+' => 'Type d\image', + 'Class:ContainerImage/Attribute:software_id' => 'Logiciel', + 'Class:ContainerImage/Attribute:software_id+' => '', + 'Class:ContainerImage/Attribute:containerapplications_list' => 'Applications conteneurisées', + 'Class:ContainerImage/Attribute:containerapplications_list+' => 'Les applications qui utilisent cette image', +]); + +// +// Class Container Application +// + +Dict::Add('FR FR', 'French', 'Français', [ + 'Class:ContainerApplication/Name' => '%1$s', + 'Class:ContainerApplication/ComplementaryName' => '%1$s', + 'Class:ContainerApplication' => 'Application Conteneurisée', + 'Class:ContainerApplication+' => 'Une application déployée sur une Plateforme de Conteneurisation', + 'Class:ContainerApplication/Attribute:descriptor' => 'Fichier de déploiement', + 'Class:ContainerApplication/Attribute:descriptor+' => 'Fichier décrivant la manière de déployer l\'application sur la plateforme de conteneurisation (par exemple, Docker Compose, Helm Chart, etc.)', + 'Class:ContainerApplication/Attribute:containervirtualhost_id' => 'Hôte', + 'Class:ContainerApplication/Attribute:containervirtualhost_id+' => 'Plateforme de conteneurisation sur laquelle cette application est déployée', + 'Class:ContainerApplication/Attribute:containertype_id' => 'Type de conteneur', + 'Class:ContainerApplication/Attribute:containertype_id+' => 'Typologie de plateforme de conteneurisation', + 'Class:ContainerApplication/Attribute:containerimages_list' => 'Images', + 'Class:ContainerApplication/Attribute:containerimages_list+' => 'Images des conteneurs constitutifs de cette application', +]); + +// +// Class: lnkContainerApplicationToImage +// + +Dict::Add('FR FR', 'French', 'Français', [ + 'Class:lnkContainerApplicationToImage' => 'Lien Application / Image pour Conteneur', + 'Class:lnkContainerApplicationToImage+' => '', + 'Class:lnkContainerApplicationToImage/Name' => '%1$s / %2$s', + 'Class:lnkContainerApplicationToImage/Name+' => '', + 'Class:lnkContainerApplicationToImage/Attribute:containerapplication_id' => 'Application conteneurisée', + 'Class:lnkContainerApplicationToImage/Attribute:containerapplication_id+' => 'Application qui utilise cette image', + 'Class:lnkContainerApplicationToImage/Attribute:containerimage_id' => 'Image pour conteneur', + 'Class:lnkContainerApplicationToImage/Attribute:containerimage_id+' => 'Une image qui contribue à l\'application', +]); + +// +// Class Container Virtual Host +// + +Dict::Add('FR FR', 'French', 'Français', [ + 'Class:ContainerVirtualHost/Name' => '%1$s', + 'Class:ContainerVirtualHost/ComplementaryName' => '', + 'Class:ContainerVirtualHost' => 'Plateforme de Conteneurisation', + 'Class:ContainerVirtualHost+' => 'Plateforme sur laquelle des applications s\'exécutent dans des conteneurs', + 'Class:ContainerVirtualHost/Attribute:containertype_id' => 'Type de plateforme', + 'Class:ContainerVirtualHost/Attribute:containertype_id+' => 'Technologie de conteneurisation utilisée', + 'Class:ContainerVirtualHost/Attribute:status' => 'État', + 'Class:ContainerVirtualHost/Attribute:status+' => 'État de la plateforme de conteneurisation', + 'Class:ContainerVirtualHost/Attribute:containerapplications_list' => 'Applications', + 'Class:ContainerVirtualHost/Attribute:containerapplications_list+' => 'Applications qui sont déployées sur cette plateforme', + 'ContainerVirtualHost:baseinfo' => 'Informations générales', + 'ContainerVirtualHost:moreinfo' => 'Spécificités de la conteneurisation', +]); + +// +// Class Container Host +// + +Dict::Add('FR FR', 'French', 'Français', [ + 'Class:ContainerHost/Name' => '%1$s', + 'Class:ContainerHost/ComplementaryName' => '%1$s-%2$s', + 'Class:ContainerHost' => 'Hôte pour Conteneurs', + 'Class:ContainerHost+' => 'Logiciel hôte dédié à l\'exécution de conteneurs. C\'est l\'élément de base d\'une Plateforme de Conteneurisation', + 'Class:ContainerHost/Attribute:containercluster_id' => 'Grappe pour conteneurs', + 'Class:ContainerHost/Attribute:containercluster_id+' => 'Grappe d\'hôtes pour conteneurs', + 'Class:ContainerHost/Attribute:role' => 'Rôle', + 'Class:ContainerHost/Attribute:role+' => 'Rôle de cet hôte au sein de la grappe : Maître ou Esclave. Autonome en l\'absence de grappe', + 'Class:ContainerHost/Attribute:role/Value:master' => 'Maître', + 'Class:ContainerHost/Attribute:role/Value:worker' => 'Esclave', + 'Class:ContainerHost/Attribute:role/Value:standalone' => 'Autonome', + 'Class:ContainerHost/Attribute:system_id' => 'Système', + 'Class:ContainerHost/Attribute:system_id+' => 'Le système sur lequel cet hôte tourne. Cela peut être un Serveur, une Machine Virtuelle ou un Nuage', +]); + +// +// Class Container Cluster +// + +Dict::Add('FR FR', 'French', 'Français', [ + 'Class:ContainerCluster/Name' => '%1$s', + 'Class:ContainerCluster/ComplementaryName' => '', + 'Class:ContainerCluster' => 'Grappe pour Conteneurs', + 'Class:ContainerCluster+' => 'Plateforme de Conteneurisation constitué d\'une grappe d\'Hôtes pour Conteneurs', + 'Class:ContainerCluster/Attribute:redundancy' => 'Configuration de la redondance', + 'Class:ContainerCluster/Attribute:redundancy/disabled' => 'La grappe est opérationnelle si tous les hôtes qui la composent sont opérationnels', + 'Class:ContainerCluster/Attribute:redundancy/count' => 'Nombre minimal d\'hôtes pour que la grappe soit opérationnelle : %1$s', + 'Class:ContainerCluster/Attribute:redundancy/percent' => 'Pourcentage minimal d\'hôtes pour que la grappe soit opérationnelle : %1$s %%', + 'Class:ContainerCluster/Attribute:containerhosts_list' => 'Hôtes pour conteneurs', + 'Class:ContainerCluster/Attribute:containerhosts_list+' => 'Hôtes composant cette grappe', +]); + +// +// Class Container Type +// + +Dict::Add('FR FR', 'French', 'Français', [ + 'Class:ContainerType/Name' => '%1$s', + 'Class:ContainerType/ComplementaryName' => '', + 'Class:ContainerType' => 'Type de conteneurisation', + 'Class:ContainerType+' => 'Technologie de conteneurisation', +]); + +// +// Class Container Image Type +// + +Dict::Add('FR FR', 'French', 'Français', [ + 'Class:ContainerImageType/Name' => '%1$s', + 'Class:ContainerImageType/ComplementaryName' => '', + 'Class:ContainerImageType' => 'Type d\'image', + 'Class:ContainerImageType+' => 'Typologie d\'images pour container', +]); diff --git a/datamodels/2.x/itop-container-mgmt/images/icons8-application-container.svg b/datamodels/2.x/itop-container-mgmt/images/icons8-application-container.svg new file mode 100644 index 000000000..01ef18e4f --- /dev/null +++ b/datamodels/2.x/itop-container-mgmt/images/icons8-application-container.svg @@ -0,0 +1,346 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/datamodels/2.x/itop-container-mgmt/images/icons8-cloud.svg b/datamodels/2.x/itop-container-mgmt/images/icons8-cloud.svg new file mode 100644 index 000000000..5132b6dbc --- /dev/null +++ b/datamodels/2.x/itop-container-mgmt/images/icons8-cloud.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/datamodels/2.x/itop-container-mgmt/images/icons8-cluster-container.svg b/datamodels/2.x/itop-container-mgmt/images/icons8-cluster-container.svg new file mode 100644 index 000000000..81e577756 --- /dev/null +++ b/datamodels/2.x/itop-container-mgmt/images/icons8-cluster-container.svg @@ -0,0 +1,524 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/datamodels/2.x/itop-container-mgmt/images/icons8-host-container.svg b/datamodels/2.x/itop-container-mgmt/images/icons8-host-container.svg new file mode 100644 index 000000000..6477f1831 --- /dev/null +++ b/datamodels/2.x/itop-container-mgmt/images/icons8-host-container.svg @@ -0,0 +1,275 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/datamodels/2.x/itop-container-mgmt/images/icons8-image-container.svg b/datamodels/2.x/itop-container-mgmt/images/icons8-image-container.svg new file mode 100644 index 000000000..0982e316a --- /dev/null +++ b/datamodels/2.x/itop-container-mgmt/images/icons8-image-container.svg @@ -0,0 +1,336 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/datamodels/2.x/itop-container-mgmt/module.itop-container-mgmt.php b/datamodels/2.x/itop-container-mgmt/module.itop-container-mgmt.php new file mode 100644 index 000000000..0666e7165 --- /dev/null +++ b/datamodels/2.x/itop-container-mgmt/module.itop-container-mgmt.php @@ -0,0 +1,52 @@ + 'Container management', + 'category' => 'business', + + // Setup + // + 'dependencies' => [ + 'itop-virtualization-mgmt/3.3.0', + ], + 'mandatory' => false, + 'visible' => true, + + // Components + // + 'datamodel' => [ + + ], + 'webservice' => [ + + ], + 'data.struct' => [ + // add your 'structure' definition XML files here, + 'data/en_us.data.itop-container-type.xml', + 'data/en_us.data.itop-container-image-type.xml', + ], + '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/itop-core-update/module.itop-core-update.php b/datamodels/2.x/itop-core-update/module.itop-core-update.php index 9e4272e34..d243de687 100644 --- a/datamodels/2.x/itop-core-update/module.itop-core-update.php +++ b/datamodels/2.x/itop-core-update/module.itop-core-update.php @@ -30,7 +30,7 @@ SetupWebPage::AddModule( // Identification // 'label' => 'iTop Core Update', - 'category' => 'business', + 'category' => 'Application management', // Setup // diff --git a/datamodels/2.x/itop-datacenter-mgmt/datamodel.itop-datacenter-mgmt.xml b/datamodels/2.x/itop-datacenter-mgmt/datamodel.itop-datacenter-mgmt.xml index b46d0f1b6..e3d2323cf 100755 --- a/datamodels/2.x/itop-datacenter-mgmt/datamodel.itop-datacenter-mgmt.xml +++ b/datamodels/2.x/itop-datacenter-mgmt/datamodel.itop-datacenter-mgmt.xml @@ -57,47 +57,77 @@
- + 10 + + + 10 + + + 10 + + + 20 + + + 30 + + + 40 + + + 50 + + + + + 20 + + + 60 + + + 70 + + + 80 + + + 90 + + + 100 + + + + - + 20 - - - 30 - - - 40 - - - 50 - - - 60 - - - 70 - - - 80 - - - 90 - - - 100 - - - 110 - - - 120 - - - 130 - - - 140 + + + 10 + + + 110 + + + 120 + + + 130 + + + + + 20 + + + 140 + + + + 150 @@ -257,50 +287,80 @@
- + 10 + + + 10 + + + 10 + + + 20 + + + 30 + + + 40 + + + 50 + + + 60 + + + + + 20 + + + 70 + + + 80 + + + 90 + + + 100 + + + 110 + + + + - + 20 - - - 30 - - - 40 - - - 50 - - - 60 - - - 70 - - - 80 - - - 90 - - - 100 - - - 110 - - - 120 - - - 130 - - - 140 - - - 150 + + + 10 + + + 120 + + + 130 + + + 140 + + + + + 20 + + + 150 + + + + 160 @@ -440,44 +500,74 @@
- + 10 + + + 10 + + + 10 + + + 20 + + + 30 + + + 40 + + + 50 + + + + + 20 + + + 60 + + + 70 + + + 80 + + + 90 + + + + - + 20 - - - 30 - - - 40 - - - 50 - - - 60 - - - 70 - - - 80 - - - 90 - - - 100 - - - 110 - - - 120 - - - 130 + + + 10 + + + 100 + + + 110 + + + 120 + + + + + 20 + + + 130 + + + + 140 @@ -613,44 +703,74 @@
- + 10 + + + 10 + + + 10 + + + 20 + + + 30 + + + 40 + + + 50 + + + + + 20 + + + 60 + + + 70 + + + 80 + + + 90 + + + + - + 20 - - - 30 - - - 40 - - - 50 - - - 60 - - - 70 - - - 80 - - - 90 - - - 100 - - - 110 - - - 120 - - - 130 + + + 10 + + + 100 + + + 110 + + + 120 + + + + + 20 + + + 130 + + + + 140 @@ -806,50 +926,80 @@
- + 10 + + + 10 + + + 10 + + + 20 + + + 30 + + + 40 + + + 50 + + + 60 + + + + + 20 + + + 70 + + + 80 + + + 90 + + + 100 + + + 110 + + + + - + 20 - - - 30 - - - 40 - - - 50 - - - 60 - - - 70 - - - 80 - - - 90 - - - 100 - - - 110 - - - 120 - - - 130 - - - 140 - - - 150 + + + 10 + + + 120 + + + 130 + + + 140 + + + + + 20 + + + 150 + + + + 160 diff --git a/datamodels/2.x/itop-endusers-devices/datamodel.itop-endusers-devices.xml b/datamodels/2.x/itop-endusers-devices/datamodel.itop-endusers-devices.xml index 14cb1a84b..2014ea758 100755 --- a/datamodels/2.x/itop-endusers-devices/datamodel.itop-endusers-devices.xml +++ b/datamodels/2.x/itop-endusers-devices/datamodel.itop-endusers-devices.xml @@ -193,47 +193,77 @@
- + 10 + + + 10 + + + 10 + + + 20 + + + 30 + + + 40 + + + 50 + + + + + 20 + + + 60 + + + 70 + + + 80 + + + 90 + + + 100 + + + + - + 20 - - - 30 - - - 40 - - - 50 - - - 60 - - - 70 - - - 80 - - - 90 - - - 100 - - - 110 - - - 120 - - - 130 - - - 140 + + + 10 + + + 110 + + + 120 + + + 130 + + + + + 20 + + + 140 + + + + 150 @@ -374,53 +404,83 @@
- + 10 + + + 10 + + + 10 + + + 20 + + + 30 + + + 40 + + + 50 + + + + + 20 + + + 60 + + + 70 + + + 80 + + + 90 + + + 100 + + + 110 + + + 120 + + + + - + 20 - - - 30 - - - 40 - - - 50 - - - 60 - - - 70 - - - 80 - - - 90 - - - 100 - - - 110 - - - 120 - - + + + 10 + + 130 - - + + 140 - - - 150 - - - 160 + + + 150 + + + + + 20 + + + 160 + + + + 170 @@ -553,47 +613,77 @@
- + 10 + + + 10 + + + 10 + + + 20 + + + 30 + + + 40 + + + 50 + + + + + 20 + + + 60 + + + 70 + + + 80 + + + 90 + + + 100 + + + + - + 20 - - - 30 - - - 40 - - - 50 - - - 60 - - - 70 - - - 80 - - - 90 - - - 100 - - + + + 10 + + 110 - - + + 120 - - - 130 - - - 140 + + + 130 + + + + + 20 + + + 140 + + + + 150 @@ -722,44 +812,74 @@
- + 10 + + + 10 + + + 10 + + + 20 + + + 30 + + + 40 + + + 50 + + + + + 20 + + + 60 + + + 70 + + + 80 + + + 90 + + + + - + 20 - - - 30 - - - 40 - - - 50 - - - 60 - - - 70 - - - 80 - - - 90 - - + + + 10 + + 100 - - + + 110 - - - 120 - - - 130 + + + 120 + + + + + 20 + + + 130 + + + + 140 @@ -938,23 +1058,8 @@
- - 5 - - - 10 - - - 20 - - - 40 - - - 50 - - 80 + 10 10 @@ -1011,7 +1116,7 @@ - 90 + 20 10 @@ -1037,6 +1142,21 @@ + + 50 + + + 80 + + + 90 + + + 100 + + + 110 +
@@ -1159,20 +1279,8 @@
- - 10 - - - 20 - - - 40 - - - 50 - - 80 + 10 10 @@ -1214,7 +1322,7 @@ - 90 + 20 10 @@ -1240,6 +1348,18 @@ + + 80 + + + 90 + + + 100 + + + 110 +
@@ -1359,44 +1479,74 @@
- + 10 + + + 10 + + + 10 + + + 20 + + + 30 + + + 40 + + + 50 + + + + + 20 + + + 60 + + + 70 + + + 80 + + + 90 + + + + - + 20 - - - 30 - - - 40 - - - 50 - - - 60 - - - 70 - - - 80 - - - 90 - - + + + 10 + + 100 - - + + 110 - - - 120 - - - 130 + + + 120 + + + + + 20 + + + 130 + + + + 140 diff --git a/datamodels/2.x/itop-faq-light/dictionaries/fr.dict.itop-faq-light.php b/datamodels/2.x/itop-faq-light/dictionaries/fr.dict.itop-faq-light.php index 9c7ad2e3d..f795b6cdc 100644 --- a/datamodels/2.x/itop-faq-light/dictionaries/fr.dict.itop-faq-light.php +++ b/datamodels/2.x/itop-faq-light/dictionaries/fr.dict.itop-faq-light.php @@ -19,7 +19,7 @@ Dict::Add('FR FR', 'French', 'Français', [ 'Class:FAQ/Attribute:summary+' => '', 'Class:FAQ/Attribute:description' => 'Description', 'Class:FAQ/Attribute:description+' => '', - 'Class:FAQ/Attribute:category_id' => 'Categorie', + 'Class:FAQ/Attribute:category_id' => 'Catégorie', 'Class:FAQ/Attribute:category_id+' => '', 'Class:FAQ/Attribute:category_name' => 'Nom catégorie', 'Class:FAQ/Attribute:category_name+' => '', diff --git a/datamodels/2.x/itop-hub-connector/hubnewsroomprovider.class.inc.php b/datamodels/2.x/itop-hub-connector/hubnewsroomprovider.class.inc.php index 17c0eca2f..5ddef4e85 100644 --- a/datamodels/2.x/itop-hub-connector/hubnewsroomprovider.class.inc.php +++ b/datamodels/2.x/itop-hub-connector/hubnewsroomprovider.class.inc.php @@ -18,7 +18,7 @@ class HubNewsroomProvider extends NewsroomProviderBase * {@inheritDoc} * @see NewsroomProviderBase::IsApplicable() */ - public function IsApplicable(User $oUser = null) + public function IsApplicable(?User $oUser = null) { if ($oUser !== null) { return UserRights::IsAdministrator($oUser); diff --git a/datamodels/2.x/itop-hub-connector/module.itop-hub-connector.php b/datamodels/2.x/itop-hub-connector/module.itop-hub-connector.php index 70521511c..4f6702167 100644 --- a/datamodels/2.x/itop-hub-connector/module.itop-hub-connector.php +++ b/datamodels/2.x/itop-hub-connector/module.itop-hub-connector.php @@ -37,6 +37,10 @@ SetupWebPage::AddModule( // add your sample data XML files here, ], + 'delegated_authentication_endpoints' => [ + 'ajax.php', + ], + // Documentation // 'doc.manual_setup' => '', // hyperlink to manual setup documentation, if any diff --git a/datamodels/2.x/itop-portal-base/portal/public/css/components/_progress-bar.scss b/datamodels/2.x/itop-portal-base/portal/public/css/components/_progress-bar.scss index 97f3cc9d9..4c08fbdd0 100644 --- a/datamodels/2.x/itop-portal-base/portal/public/css/components/_progress-bar.scss +++ b/datamodels/2.x/itop-portal-base/portal/public/css/components/_progress-bar.scss @@ -10,8 +10,6 @@ $ipb-progress--bar--border-radius: $ipb-progress--border-radius !default; } .ipb-progress--bar, .progress-bar { - background-color: $ipb-color-primary-600; - color: #ffffff; line-height: $ipb-progress--bar--line-height; border-radius: $ipb-progress--bar--border-radius; diff --git a/datamodels/2.x/itop-portal-base/portal/public/css/themes/components/_progress-bar.scss b/datamodels/2.x/itop-portal-base/portal/public/css/themes/components/_progress-bar.scss index de4287dce..22c16dd3c 100644 --- a/datamodels/2.x/itop-portal-base/portal/public/css/themes/components/_progress-bar.scss +++ b/datamodels/2.x/itop-portal-base/portal/public/css/themes/components/_progress-bar.scss @@ -9,6 +9,6 @@ $ipb-progress--bar--color: $ipb-color-white-100 !default; } .ipb-progress--bar, .progress-bar { - background-color: $ipb-color-primary-700; + background-color: $ipb-progress--bar--background-color; color: $ipb-progress--bar--color; } \ No newline at end of file diff --git a/datamodels/2.x/itop-portal-base/portal/src/DataCollector/PortalCollector.php b/datamodels/2.x/itop-portal-base/portal/src/DataCollector/PortalCollector.php index 3bf050697..6ef1c4b6e 100644 --- a/datamodels/2.x/itop-portal-base/portal/src/DataCollector/PortalCollector.php +++ b/datamodels/2.x/itop-portal-base/portal/src/DataCollector/PortalCollector.php @@ -27,7 +27,7 @@ class PortalCollector extends AbstractDataCollector } /** @inheritdoc */ - public function collect(Request $request, Response $response, Throwable $exception = null): void + public function collect(Request $request, Response $response, ?Throwable $exception = null): void { $oRegister = $this->oTemplatesProviderService->GetRegister(); $aTemplatesDefinitions = $oRegister->GetTemplatesDefinitions(); diff --git a/datamodels/2.x/itop-portal-base/portal/src/Helper/BrowseBrickHelper.php b/datamodels/2.x/itop-portal-base/portal/src/Helper/BrowseBrickHelper.php index a646469c1..3b176bd30 100644 --- a/datamodels/2.x/itop-portal-base/portal/src/Helper/BrowseBrickHelper.php +++ b/datamodels/2.x/itop-portal-base/portal/src/Helper/BrowseBrickHelper.php @@ -317,7 +317,7 @@ class BrowseBrickHelper $aRow[$key] = [ 'level_alias' => $key, 'id' => $sCurrentObjectId, - 'name' => utils::EscapeHtml($value->Get($sNameAttCode)), + 'name' => $value->Get($sNameAttCode), 'class' => $sCurrentObjectClass, 'action_rules_token' => $this->PrepareActionRulesForItems($aItems, $key, $aLevelsProperties), 'metadata' => [ @@ -476,7 +476,7 @@ class BrowseBrickHelper $aItems[$sCurrentIndex] = [ 'level_alias' => $aCurrentRowKeys[0], 'id' => $aCurrentRowValues[0]->GetKey(), - 'name' => utils::EscapeHtml($aCurrentRowValues[0]->Get($aLevelsProperties[$aCurrentRowKeys[0]]['name_att'])), + 'name' => $aCurrentRowValues[0]->Get($aLevelsProperties[$aCurrentRowKeys[0]]['name_att']), 'class' => get_class($aCurrentRowValues[0]), 'subitems' => [], 'filter_data' => $this->GetFilterData($aLevelsProperties[$aCurrentRowKeys[0]], $aCurrentRowKeys[0], $aCurrentRowValues[0]), diff --git a/datamodels/2.x/itop-portal-base/portal/src/Helper/ObjectFormHandlerHelper.php b/datamodels/2.x/itop-portal-base/portal/src/Helper/ObjectFormHandlerHelper.php index 852ac9be7..003d5b8a9 100644 --- a/datamodels/2.x/itop-portal-base/portal/src/Helper/ObjectFormHandlerHelper.php +++ b/datamodels/2.x/itop-portal-base/portal/src/Helper/ObjectFormHandlerHelper.php @@ -129,7 +129,7 @@ class ObjectFormHandlerHelper * @throws \OQLException * @throws \Exception */ - public function HandleForm(Request $oRequest, $sMode, $sObjectClass, $sObjectId = null, array $aFormProperties = null) + public function HandleForm(Request $oRequest, $sMode, $sObjectClass, $sObjectId = null, ?array $aFormProperties = null) { $aFormData = []; $sOperation = $this->oRequestManipulator->ReadParam('operation', ''); diff --git a/datamodels/2.x/itop-portal-base/portal/src/Twig/AppVariable.php b/datamodels/2.x/itop-portal-base/portal/src/Twig/AppVariable.php index b6081d0dc..8cc112a44 100644 --- a/datamodels/2.x/itop-portal-base/portal/src/Twig/AppVariable.php +++ b/datamodels/2.x/itop-portal-base/portal/src/Twig/AppVariable.php @@ -40,7 +40,7 @@ class AppVariable implements ArrayAccess /** @var DecoratedAppVariable */ private $decorated; - public function __construct(DecoratedAppVariable $decorated, ContainerInterface $container = null) + public function __construct(DecoratedAppVariable $decorated, ?ContainerInterface $container = null) { $this->decorated = $decorated; $this->container = $container; diff --git a/datamodels/2.x/itop-portal-base/portal/src/Twig/TemplatesTwigExtension.php b/datamodels/2.x/itop-portal-base/portal/src/Twig/TemplatesTwigExtension.php index c59f439c3..125a30944 100644 --- a/datamodels/2.x/itop-portal-base/portal/src/Twig/TemplatesTwigExtension.php +++ b/datamodels/2.x/itop-portal-base/portal/src/Twig/TemplatesTwigExtension.php @@ -57,7 +57,7 @@ class TemplatesTwigExtension extends AbstractExtension * @return string the template path * @throws \ReflectionException */ - public function GetTemplate(string $sId, string $sProviderClass = self::DEFAULT_PROVIDER_CLASS, object $oProviderInstance = null): string + public function GetTemplate(string $sId, string $sProviderClass = self::DEFAULT_PROVIDER_CLASS, ?object $oProviderInstance = null): string { if ($oProviderInstance === null) { return $this->oTemplatesService->GetTemplatePath($sProviderClass, $sId); diff --git a/datamodels/2.x/itop-portal-base/portal/templates/bricks/browse/mode_list.html.twig b/datamodels/2.x/itop-portal-base/portal/templates/bricks/browse/mode_list.html.twig index c35e04c11..53565b0d9 100644 --- a/datamodels/2.x/itop-portal-base/portal/templates/bricks/browse/mode_list.html.twig +++ b/datamodels/2.x/itop-portal-base/portal/templates/bricks/browse/mode_list.html.twig @@ -83,11 +83,11 @@ // N°4662 - Surround tooltip with div to ensure text retrival if( (data.tooltip !== undefined) && ($('
'+data.tooltip+'
').text() !== '')) { - cellElem.html( $('').attr('data-tooltip-content', data.tooltip).attr('data-tooltip-html-enabled', true).html(data.name).prop('outerHTML') ); + cellElem.html( $('').attr('data-tooltip-content', data.tooltip).attr('data-tooltip-html-enabled', true).text(data.name).prop('outerHTML') ); } else { - cellElem.html(data.name); + cellElem.text(data.name); } // Building actions diff --git a/datamodels/2.x/itop-portal-base/portal/templates/bricks/browse/mode_mosaic.html.twig b/datamodels/2.x/itop-portal-base/portal/templates/bricks/browse/mode_mosaic.html.twig index 23d846e94..86de54e41 100644 --- a/datamodels/2.x/itop-portal-base/portal/templates/bricks/browse/mode_mosaic.html.twig +++ b/datamodels/2.x/itop-portal-base/portal/templates/bricks/browse/mode_mosaic.html.twig @@ -206,7 +206,7 @@ if( (item.name !== undefined) && (item.name !== '') ) { iItemFlags += 1; - textWrapperElem.append( $('
').addClass('mosaic-item-name').html(item.name) ); + textWrapperElem.append( $('
').addClass('mosaic-item-name').text(item.name) ); } // - Adding description if( (item.description !== undefined) && (item.description !== '') ) diff --git a/datamodels/2.x/itop-portal-base/portal/templates/bricks/browse/mode_tree.html.twig b/datamodels/2.x/itop-portal-base/portal/templates/bricks/browse/mode_tree.html.twig index c65983266..04ff2e573 100644 --- a/datamodels/2.x/itop-portal-base/portal/templates/bricks/browse/mode_tree.html.twig +++ b/datamodels/2.x/itop-portal-base/portal/templates/bricks/browse/mode_tree.html.twig @@ -238,7 +238,9 @@ { case '{{ constant('Combodo\\iTop\\Portal\\Brick\\BrowseBrick::ENUM_ACTION_DRILLDOWN') }}': spanElem.addClass('tree-toggle'); - nameElem.html(''+item.name+''); + var drilldownIconElem = $('').addClass('glyphicon '+sNodeCollapsedClass).attr('aria-hidden', 'true'); + var drilldownTextElem = $('').addClass('list-group-item-text').text(nameElem.text()); + nameElem.empty().append(drilldownIconElem).append(drilldownTextElem); break; case '{{ constant('Combodo\\iTop\\Portal\\Brick\\BrowseBrick::ENUM_ACTION_VIEW') }}': url = '{{ app.url_generator.generate('p_object_view', {'sObjectClass': '-objectClass-', 'sObjectId': '-objectId-'})|raw }}'.replace(/-objectClass-/, item.class).replace(/-objectId-/, item.id); @@ -280,7 +282,7 @@ { nameElem.append($(''+item.description+'')); } - + if(levelActionsKeys.length > 1) { // Retrieving secondary action (Now we also display primary action) diff --git a/datamodels/2.x/itop-portal-base/portal/templates/bricks/manage/popup-export-excel.html.twig b/datamodels/2.x/itop-portal-base/portal/templates/bricks/manage/popup-export-excel.html.twig index 59cfee2bd..e5eb1308e 100644 --- a/datamodels/2.x/itop-portal-base/portal/templates/bricks/manage/popup-export-excel.html.twig +++ b/datamodels/2.x/itop-portal-base/portal/templates/bricks/manage/popup-export-excel.html.twig @@ -11,7 +11,7 @@