Merge remote-tracking branch 'origin/issue-1100'

main
Adriaan de Groot 6 years ago
commit 713370da55

@ -128,7 +128,8 @@ branding: default
# If this is set to true, Calamares will show an "Are you sure?" prompt right
# before each execution phase, i.e. at points of no return. If this is set to
# false, no prompt is shown. Default is false.
# false, no prompt is shown. Default is false, but Calamares will complain if
# this is not explicitly set.
#
# YAML: boolean.
prompt-install: false
@ -142,16 +143,23 @@ prompt-install: false
# setting. (e.g. partitioning seems like a bad idea, since that is expected to
# have been done already)
#
# Default is false (for a normal installer).
# Default is false (for a normal installer), but Calamares will complain if
# this is not explicitly set.
#
# YAML: boolean.
dont-chroot: false
# If this is set to true, Calamares refers to itself as a "setup program"
# rather than an "installer". Defaults to the value of dont-chroot, but
# Calamares will complain if this is not explicitly set.
# oem-setup: true
# If this is set to true, the "Cancel" button will be disabled.
# This can be useful if when e.g. calamares is used as a post-install configuration
# tool and you require the user to go through all the configuration steps.
# This can be useful if when e.g. Calamares is used as a post-install
# configuration tool and you require the user to go through all the
# configuration steps.
#
# Default is false.
# Default is false, but Calamares will complain if this is not explicitly set.
#
# YAML: boolean.
disable-cancel: false

@ -2,6 +2,7 @@
*
* Copyright 2014-2015, Teo Mrnjavac <teo@kde.org>
* Copyright 2017-2018, Adriaan de Groot <groot@kde.org>
* Copyright 2019, Collabora Ltd <arnaud.ferraris@collabora.com>
*
* Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -53,8 +54,10 @@ CalamaresWindow::CalamaresWindow( QWidget* parent )
, m_viewManager( nullptr )
{
CALAMARES_RETRANSLATE(
setWindowTitle( tr( "%1 Installer" )
.arg( *Calamares::Branding::ProductName ) );
setWindowTitle( Calamares::Settings::instance()->isSetupMode()
? tr( "%1 Setup Program" ).arg( *Calamares::Branding::ProductName )
: tr( "%1 Installer" ).arg( *Calamares::Branding::ProductName )
);
)
const Calamares::Branding* const branding = Calamares::Branding::instance();

@ -35,7 +35,7 @@ hasValue( const YAML::Node& v )
return v.IsDefined() && !v.IsNull();
}
/** Helper function to grab a QString out of the config, and to warn if not present. */
/** @brief Helper function to grab a QString out of the config, and to warn if not present. */
static QString
requireString( const YAML::Node& config, const char* key )
{
@ -49,7 +49,7 @@ requireString( const YAML::Node& config, const char* key )
}
}
/** Helper function to grab a bool out of the config, and to warn if not present. */
/** @brief Helper function to grab a bool out of the config, and to warn if not present. */
static bool
requireBool( const YAML::Node& config, const char* key, bool d )
{
@ -204,6 +204,7 @@ Settings::Settings( const QString& settingsFilePath,
m_brandingComponentName = requireString( config, "branding" );
m_promptInstall = requireBool( config, "prompt-install", false );
m_doChroot = !requireBool( config, "dont-chroot", false );
m_isSetupMode = requireBool( config, "oem-setup", !m_doChroot );
m_disableCancel = requireBool( config, "disable-cancel", false );
}
catch ( YAML::Exception& e )

@ -57,6 +57,15 @@ public:
bool debugMode() const;
bool doChroot() const;
/** @brief Distinguish between "install" and "setup" modes.
*
* This influences user-visible strings, for instance using the
* word "setup" instead of "install" where relevant.
*
* NOTE: it's a synonym for !doChroot() for now, but may become
* an independent setting.
*/
bool isSetupMode() const { return m_isSetupMode; }
bool disableCancel() const;
@ -72,6 +81,7 @@ private:
bool m_debug;
bool m_doChroot;
bool m_isSetupMode;
bool m_promptInstall;
bool m_disableCancel;
};

@ -74,7 +74,10 @@ ViewManager::ViewManager( QObject* parent )
m_back->setText( tr( "&Back" ) );
m_next->setText( tr( "&Next" ) );
m_quit->setText( tr( "&Cancel" ) );
m_quit->setToolTip( tr( "Cancel installation without changing the system." ) );
QString tooltip = Calamares::Settings::instance()->isSetupMode()
? tr( "Cancel setup without changing the system." )
: tr( "Cancel installation without changing the system." );
m_quit->setToolTip( tooltip );
)
QBoxLayout* bottomLayout = new QHBoxLayout;
@ -159,10 +162,13 @@ ViewManager::onInstallationFailed( const QString& message, const QString& detail
cDebug() << "- message:" << message;
cDebug() << "- details:" << details;
QString heading = Calamares::Settings::instance()->isSetupMode()
? tr( "Setup Failed" )
: tr( "Installation Failed" );
QMessageBox* msgBox = new QMessageBox();
msgBox->setIcon( QMessageBox::Critical );
msgBox->setWindowTitle( tr( "Error" ) );
msgBox->setText( "<strong>" + tr( "Installation Failed" ) + "</strong>" );
msgBox->setText( "<strong>" + heading + "</strong>" );
msgBox->setStandardButtons( QMessageBox::Close );
msgBox->button( QMessageBox::Close )->setText( tr( "&Close" ) );
@ -180,6 +186,8 @@ ViewManager::onInstallationFailed( const QString& message, const QString& detail
void
ViewManager::onInitFailed( const QStringList& modules)
{
// Because this means the installer / setup program is broken by the distributor,
// don't bother being precise about installer / setup wording.
QString title( tr( "Calamares Initialization Failed" ) );
QString description( tr( "%1 can not be installed. Calamares was unable to load all of the configured modules. This is a problem with the way Calamares is being used by the distribution." ) );
QString detailString;
@ -236,15 +244,25 @@ ViewManager::next()
// Depending on Calamares::Settings, we show an "are you sure" prompt or not.
if ( Calamares::Settings::instance()->showPromptBeforeExecution() && stepNextWillExecute( m_steps, m_currentStep ) )
{
QString title = Calamares::Settings::instance()->isSetupMode()
? tr( "Continue with setup?" )
: tr( "Continue with installation?" );
QString question = Calamares::Settings::instance()->isSetupMode()
? tr( "The %1 setup program is about to make changes to your "
"disk in order to set up %2.<br/><strong>You will not be able "
"to undo these changes.</strong>" )
: tr( "The %1 installer is about to make changes to your "
"disk in order to install %2.<br/><strong>You will not be able "
"to undo these changes.</strong>" );
QString confirm = Calamares::Settings::instance()->isSetupMode()
? tr( "&Set up now" )
: tr( "&Install now" );
int reply =
QMessageBox::question( m_widget,
tr( "Continue with setup?" ),
tr( "The %1 installer is about to make changes to your "
"disk in order to install %2.<br/><strong>You will not be able "
"to undo these changes.</strong>" )
.arg( *Calamares::Branding::ShortProductName )
.arg( *Calamares::Branding::ShortVersionedName ),
tr( "&Install now" ),
title,
question.arg( *Calamares::Branding::ShortProductName, *Calamares::Branding::ShortVersionedName ),
confirm,
tr( "Go &back" ),
QString(),
0,
@ -277,15 +295,25 @@ ViewManager::next()
void
ViewManager::updateButtonLabels()
{
QString next = Calamares::Settings::instance()->isSetupMode()
? tr( "&Set up" )
: tr( "&Install" );
QString complete = Calamares::Settings::instance()->isSetupMode()
? tr( "Setup is complete. Close the setup program." )
: tr( "The installation is complete. Close the installer." );
QString quit = Calamares::Settings::instance()->isSetupMode()
? tr( "Cancel setup without changing the system." )
: tr( "Cancel installation without changing the system." );
if ( stepNextWillExecute( m_steps, m_currentStep ) )
m_next->setText( tr( "&Install" ) );
m_next->setText( next );
else
m_next->setText( tr( "&Next" ) );
if ( m_currentStep == m_steps.count() -1 && m_steps.last()->isAtEnd() )
{
m_quit->setText( tr( "&Done" ) );
m_quit->setToolTip( tr( "The installation is complete. Close the installer." ) );
m_quit->setToolTip( complete );
if (Calamares::Settings::instance()->disableCancel())
m_quit->setVisible( true );
}
@ -294,7 +322,7 @@ ViewManager::updateButtonLabels()
if (Calamares::Settings::instance()->disableCancel())
m_quit->setVisible( false );
m_quit->setText( tr( "&Cancel" ) );
m_quit->setToolTip( tr( "Cancel installation without changing the system." ) );
m_quit->setToolTip( quit );
}
}
@ -329,10 +357,17 @@ bool ViewManager::confirmCancelInstallation()
if ( !( m_currentStep == m_steps.count() -1 &&
m_steps.last()->isAtEnd() ) )
{
QString title = Calamares::Settings::instance()->isSetupMode()
? tr( "Cancel setup?" )
: tr( "Cancel installation?" );
QString question = Calamares::Settings::instance()->isSetupMode()
? tr( "Do you really want to cancel the current setup process?\n"
"The setup program will quit and all changes will be lost." )
: tr( "Do you really want to cancel the current install process?\n"
"The installer will quit and all changes will be lost." );
QMessageBox mb( QMessageBox::Question,
tr( "Cancel installation?" ),
tr( "Do you really want to cancel the current install process?\n"
"The installer will quit and all changes will be lost." ),
title,
question,
QMessageBox::Yes | QMessageBox::No,
m_widget );
mb.setDefaultButton( QMessageBox::No );

@ -2,6 +2,7 @@
*
* Copyright 2014-2015, Teo Mrnjavac <teo@kde.org>
* Copyright 2017-2018, Adriaan de Groot <groot@kde.org>
* Copyright 2019, Collabora Ltd <arnaud.ferraris@collabora.com>
*
* Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -33,7 +34,7 @@
#include <QProcess>
#include "Branding.h"
#include "Settings.h"
FinishedPage::FinishedPage( QWidget* parent )
: QWidget( parent )
@ -48,12 +49,33 @@ FinishedPage::FinishedPage( QWidget* parent )
CALAMARES_RETRANSLATE(
ui->retranslateUi( this );
ui->mainText->setText( tr( "<h1>All done.</h1><br/>"
"%1 has been installed on your computer.<br/>"
"You may now restart into your new system, or continue "
"using the %2 Live environment." )
.arg( *Calamares::Branding::VersionedName )
.arg( *Calamares::Branding::ProductName ) );
if ( Calamares::Settings::instance()->isSetupMode() )
{
ui->mainText->setText( tr( "<h1>All done.</h1><br/>"
"%1 has been set up on your computer.<br/>"
"You may now start using your new system." )
.arg( *Calamares::Branding::VersionedName )
.arg( *Calamares::Branding::ProductName ) );
ui->restartCheckBox->setToolTip( tr ( "<html><head/><body>"
"<p>When this box is checked, your system will "
"restart immediately when you click on "
"<span style=\"font-style:italic;\">Done</span> "
"or close the setup program.</p></body></html>" ) );
}
else
{
ui->mainText->setText( tr( "<h1>All done.</h1><br/>"
"%1 has been installed on your computer.<br/>"
"You may now restart into your new system, or continue "
"using the %2 Live environment." )
.arg( *Calamares::Branding::VersionedName )
.arg( *Calamares::Branding::ProductName ) );
ui->restartCheckBox->setToolTip( tr ( "<html><head/><body>"
"<p>When this box is checked, your system will "
"restart immediately when you click on "
"<span style=\"font-style:italic;\">Done</span> "
"or close the installer.</p></body></html>" ) );
}
)
}
@ -106,10 +128,17 @@ void
FinishedPage::onInstallationFailed( const QString& message, const QString& details )
{
Q_UNUSED( details );
ui->mainText->setText( tr( "<h1>Installation Failed</h1><br/>"
"%1 has not been installed on your computer.<br/>"
"The error message was: %2." )
.arg( *Calamares::Branding::VersionedName )
.arg( message ) );
if ( Calamares::Settings::instance()->isSetupMode() )
ui->mainText->setText( tr( "<h1>Setup Failed</h1><br/>"
"%1 has not been set up on your computer.<br/>"
"The error message was: %2." )
.arg( *Calamares::Branding::VersionedName )
.arg( message ) );
else
ui->mainText->setText( tr( "<h1>Installation Failed</h1><br/>"
"%1 has not been installed on your computer.<br/>"
"The error message was: %2." )
.arg( *Calamares::Branding::VersionedName )
.arg( message ) );
setRestartNowEnabled( false );
}

@ -92,7 +92,7 @@
<item>
<widget class="QCheckBox" name="restartCheckBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;When this box is checked, your system will restart immediately when you click on &lt;span style=&quot; font-style:italic;&quot;&gt;Done&lt;/span&gt; or close the installer.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;Restart checkbox tooltip&gt;</string>
</property>
<property name="text">
<string>&amp;Restart now</string>

@ -2,6 +2,7 @@
*
* Copyright 2014-2015, Teo Mrnjavac <teo@kde.org>
* Copyright 2017, Adriaan de Groot <groot@kde.org>
* Copyright 2019, Collabora Ltd <arnaud.ferraris@collabora.com>
*
* Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -29,6 +30,7 @@
#include <QVariantMap>
#include "Branding.h"
#include "Settings.h"
FinishedViewStep::FinishedViewStep( QObject* parent )
: Calamares::ViewStep( parent )
@ -109,8 +111,12 @@ FinishedViewStep::sendNotification()
QString( "Calamares" ),
QVariant( 0U ),
QString( "calamares" ),
tr( "Installation Complete" ),
tr( "The installation of %1 is complete." ).arg( *Calamares::Branding::VersionedName ),
Calamares::Settings::instance()->isSetupMode()
? tr( "Setup Complete" )
: tr( "Installation Complete" ),
Calamares::Settings::instance()->isSetupMode()
? tr( "The setup of %1 is complete." ).arg( *Calamares::Branding::VersionedName )
: tr( "The installation of %1 is complete." ).arg( *Calamares::Branding::VersionedName ),
QStringList(),
QVariantMap(),
QVariant( 0 )

@ -1,6 +1,7 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2017-2018, Adriaan de Groot <groot@kde.org>
* Copyright 2019, Collabora Ltd <arnaud.ferraris@collabora.com>
*
* Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -22,6 +23,7 @@
#include "utils/Logger.h"
#include "utils/Retranslator.h"
#include "Settings.h"
#include <QAbstractButton>
@ -64,11 +66,18 @@ PlasmaLnfPage::PlasmaLnfPage( QWidget* parent )
CALAMARES_RETRANSLATE(
{
ui->retranslateUi( this );
ui->generalExplanation->setText( tr(
"Please choose a look-and-feel for the KDE Plasma Desktop. "
"You can also skip this step and configure the look-and-feel "
"once the system is installed. Clicking on a look-and-feel "
"selection will give you a live preview of that look-and-feel.") );
if ( Calamares::Settings::instance()->isSetupMode() )
ui->generalExplanation->setText( tr(
"Please choose a look-and-feel for the KDE Plasma Desktop. "
"You can also skip this step and configure the look-and-feel "
"once the system is set up. Clicking on a look-and-feel "
"selection will give you a live preview of that look-and-feel.") );
else
ui->generalExplanation->setText( tr(
"Please choose a look-and-feel for the KDE Plasma Desktop. "
"You can also skip this step and configure the look-and-feel "
"once the system is installed. Clicking on a look-and-feel "
"selection will give you a live preview of that look-and-feel.") );
updateThemeNames();
fillUi();
}

@ -2,6 +2,7 @@
*
* Copyright 2014-2015, Teo Mrnjavac <teo@kde.org>
* Copyright 2017, Adriaan de Groot <groot@kde.org>
* Copyright 2019, Collabora Ltd <arnaud.ferraris@collabora.com>
*
* Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -25,6 +26,7 @@
#include "utils/Retranslator.h"
#include "utils/CalamaresUtilsGui.h"
#include "utils/Logger.h"
#include "Settings.h"
#include "ViewManager.h"
#include <QBoxLayout>
@ -46,8 +48,12 @@ SummaryPage::SummaryPage( const SummaryViewStep* thisViewStep, QWidget* parent )
QLabel* headerLabel = new QLabel( this );
CALAMARES_RETRANSLATE(
headerLabel->setText( tr( "This is an overview of what will happen once you start "
"the install procedure." ) );
if ( Calamares::Settings::instance()->isSetupMode() )
headerLabel->setText( tr( "This is an overview of what will happen once you start "
"the setup procedure." ) );
else
headerLabel->setText( tr( "This is an overview of what will happen once you start "
"the install procedure." ) );
)
layout->addWidget( headerLabel );
layout->addWidget( m_scrollArea );

@ -2,6 +2,7 @@
*
* Copyright 2014-2017, Teo Mrnjavac <teo@kde.org>
* Copyright 2017-2018, Adriaan de Groot <groot@kde.org>
* Copyright 2019, Collabora Ltd <arnaud.ferraris@collabora.com>
*
* Portions from the Manjaro Installation Framework
* by Roland Singer <roland@manjaro.org>
@ -31,6 +32,7 @@
#include "utils/Logger.h"
#include "utils/CalamaresUtilsGui.h"
#include "utils/Retranslator.h"
#include "Settings.h"
#include <QBoxLayout>
#include <QLabel>
@ -106,7 +108,21 @@ UsersPage::UsersPage( QWidget* parent )
ui->hostname_extra_label_2->setMaximumWidth( 3 * boxWidth );
ui->password_extra_label_3->setMaximumWidth( 3 * boxWidth );
CALAMARES_RETRANSLATE( ui->retranslateUi( this ); )
CALAMARES_RETRANSLATE(
ui->retranslateUi( this );
if ( Calamares::Settings::instance()->isSetupMode() )
{
ui->username_extra_label_2->setText( tr( "<small>If more than one person will "
"use this computer, you can create multiple "
"accounts after setup.</small>" ) );
}
else
{
ui->username_extra_label_2->setText( tr( "<small>If more than one person will "
"use this computer, you can create multiple "
"accounts after installation.</small>" ) );
}
)
}

@ -197,7 +197,7 @@
<string notr="true">font-weight: normal</string>
</property>
<property name="text">
<string>&lt;small&gt;If more than one person will use this computer, you can set up multiple accounts after installation.&lt;/small&gt;</string>
<string>&lt;Username extra label 2 text&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>

@ -28,6 +28,7 @@
#include "utils/Retranslator.h"
#include "modulesystem/ModuleManager.h"
#include "Settings.h"
#include "ViewManager.h"
#include <QApplication>
@ -62,8 +63,18 @@ WelcomePage::WelcomePage( QWidget* parent )
<< *Calamares::Branding::VersionedName;
CALAMARES_RETRANSLATE(
ui->mainText->setText( (Calamares::Branding::instance()->welcomeStyleCalamares() ? tr( "<h1>Welcome to the Calamares installer for %1.</h1>" ) : tr( "<h1>Welcome to the %1 installer.</h1>" ))
.arg( *Calamares::Branding::VersionedName ) );
QString message;
if ( Calamares::Settings::instance()->isSetupMode() )
message = Calamares::Branding::instance()->welcomeStyleCalamares()
? tr( "<h1>Welcome to the Calamares setup program for %1.</h1>" )
: tr( "<h1>Welcome to %1 setup.</h1>" );
else
message = Calamares::Branding::instance()->welcomeStyleCalamares()
? tr( "<h1>Welcome to the Calamares installer for %1.</h1>" )
: tr( "<h1>Welcome to the %1 installer.</h1>" );
ui->mainText->setText( message.arg( *Calamares::Branding::VersionedName ) );
ui->retranslateUi( this );
)
@ -74,9 +85,11 @@ WelcomePage::WelcomePage( QWidget* parent )
connect( ui->aboutButton, &QPushButton::clicked,
this, [ this ]
{
QString title = Calamares::Settings::instance()->isSetupMode()
? tr( "About %1 setup" )
: tr( "About %1 installer" );
QMessageBox mb( QMessageBox::Information,
tr( "About %1 installer" )
.arg( CALAMARES_APPLICATION_NAME ),
title.arg( CALAMARES_APPLICATION_NAME ),
tr(
"<h1>%1</h1><br/>"
"<strong>%2<br/>"

@ -3,6 +3,7 @@
* Copyright 2014-2017, Teo Mrnjavac <teo@kde.org>
* Copyright 2017-2018, Adriaan de Groot <groot@kde.org>
* Copyright 2017, Gabriel Craciunescu <crazy@frugalware.org>
* Copyright 2019, Collabora Ltd <arnaud.ferraris@collabora.com>
*
* Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -30,7 +31,7 @@
#include "utils/Retranslator.h"
#include "utils/CalamaresUtilsSystem.h"
#include "utils/Units.h"
#include "Settings.h"
#include "JobQueue.h"
#include "GlobalStorage.h"
@ -141,7 +142,9 @@ Calamares::RequirementsList GeneralRequirements::checkRequirements()
checkEntries.append( {
entry,
[this]{ return QString(); }, //we hide it
[this]{ return tr( "The installer is not running with administrator rights." ); },
[this]{ return Calamares::Settings::instance()->isSetupMode()
? tr( "The setup program is not running with administrator rights." )
: tr( "The installer is not running with administrator rights." ); },
isRoot,
m_entriesToRequire.contains( entry )
} );
@ -149,7 +152,9 @@ Calamares::RequirementsList GeneralRequirements::checkRequirements()
checkEntries.append( {
entry,
[this]{ return QString(); }, // we hide it
[this]{ return tr( "The screen is too small to display the installer." ); },
[this]{ return Calamares::Settings::instance()->isSetupMode()
? tr( "The screen is too small to display the setup program." )
: tr( "The screen is too small to display the installer." ); },
enoughScreen,
false
} );

@ -22,6 +22,7 @@
#include "ResultWidget.h"
#include "Branding.h"
#include "Settings.h"
#include "utils/CalamaresUtilsGui.h"
#include "utils/Retranslator.h"
#include "widgets/FixedAspectRatioLabel.h"
@ -91,11 +92,16 @@ ResultsListWidget::init( const Calamares::RequirementsList& checkEntries )
if ( !requirementsSatisfied )
{
CALAMARES_RETRANSLATE(
textLabel->setText( tr( "This computer does not satisfy the minimum "
"requirements for installing %1.<br/>"
"Installation cannot continue. "
"<a href=\"#details\">Details...</a>" )
.arg( *Calamares::Branding::ShortVersionedName ) );
QString message = Calamares::Settings::instance()->isSetupMode()
? tr( "This computer does not satisfy the minimum "
"requirements for setting up %1.<br/>"
"Setup cannot continue. "
"<a href=\"#details\">Details...</a>" )
: tr( "This computer does not satisfy the minimum "
"requirements for installing %1.<br/>"
"Installation cannot continue. "
"<a href=\"#details\">Details...</a>" );
textLabel->setText( message.arg( *Calamares::Branding::ShortVersionedName ) );
)
textLabel->setOpenExternalLinks( false );
connect( textLabel, &QLabel::linkActivated,
@ -108,11 +114,16 @@ ResultsListWidget::init( const Calamares::RequirementsList& checkEntries )
else
{
CALAMARES_RETRANSLATE(
textLabel->setText( tr( "This computer does not satisfy some of the "
"recommended requirements for installing %1.<br/>"
"Installation can continue, but some features "
"might be disabled." )
.arg( *Calamares::Branding::ShortVersionedName ) );
QString message = Calamares::Settings::instance()->isSetupMode()
? tr( "This computer does not satisfy some of the "
"recommended requirements for setting up %1.<br/>"
"Setup can continue, but some features "
"might be disabled." )
: tr( "This computer does not satisfy some of the "
"recommended requirements for installing %1.<br/>"
"Installation can continue, but some features "
"might be disabled." );
textLabel->setText( message.arg( *Calamares::Branding::ShortVersionedName ) );
)
}
}

Loading…
Cancel
Save