Integrated all fossil/fuel options into the Settings dialog

runFossil now uses a bitfield to control execution options
Settings management now sucks less, (but still enough suckage remains)



FossilOrigin-Name: 91c5a65b7e4ca4801a6d7632abd7982d2063a1f3
This commit is contained in:
kostas 2011-10-19 16:30:12 +00:00
parent bff4b2967c
commit 15e3cabf23
8 changed files with 157 additions and 106 deletions

View File

@ -15,7 +15,6 @@
#include "FileActionDialog.h"
#include <QDebug>
#define SILENT_STATUS true
#define COUNTOF(array) (sizeof(array)/sizeof(array[0]))
#ifdef QT_WS_WIN
@ -110,6 +109,7 @@ static DialogAnswer DialogQuery(QWidget *parent, const QString &title, const QSt
}
//-----------------------------------------------------------------------------
#if 0 // Unused
static bool DialogQueryText(QWidget *parent, const QString &title, const QString &query, QString &text, bool isPassword=false)
{
QInputDialog dlg(parent, Qt::Sheet);
@ -128,7 +128,7 @@ static bool DialogQueryText(QWidget *parent, const QString &title, const QString
text = dlg.textValue();
return true;
}
#endif
///////////////////////////////////////////////////////////////////////////////
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
@ -297,7 +297,7 @@ bool MainWindow::openWorkspace(const QString &path)
repositoryFile = fi.absoluteFilePath();
if(!runFossil(QStringList() << "open" << QuotePath(repositoryFile), 0, false))
if(!runFossil(QStringList() << "open" << QuotePath(repositoryFile)))
{
QMessageBox::critical(this, tr("Error"), tr("Could not open repository."), QMessageBox::Ok );
return false;
@ -384,14 +384,14 @@ void MainWindow::on_actionNewRepository_triggered()
repositoryFile = path_info.absoluteFilePath();
// Create repo
if(!runFossil(QStringList() << "new" << QuotePath(repositoryFile), 0, false))
if(!runFossil(QStringList() << "new" << QuotePath(repositoryFile)))
{
QMessageBox::critical(this, tr("Error"), tr("Could not create repository."), QMessageBox::Ok );
return;
}
// Open repo
if(!runFossil(QStringList() << "open" << QuotePath(repositoryFile), 0, false))
if(!runFossil(QStringList() << "open" << QuotePath(repositoryFile)))
{
QMessageBox::critical(this, tr("Error"), tr("Could not open repository."), QMessageBox::Ok );
return;
@ -409,7 +409,7 @@ void MainWindow::on_actionCloseRepository_triggered()
return;
// Close Repo
if(!runFossil(QStringList() << "close", 0, false))
if(!runFossil(QStringList() << "close"))
{
QMessageBox::critical(this, tr("Error"), tr("Cannot close the workspace.\nAre there still uncommitted changes in available?"), QMessageBox::Ok );
return;
@ -556,7 +556,7 @@ void MainWindow::scanWorkspace()
// Retrieve the status of files tracked by fossil
QStringList res;
if(!runFossil(QStringList() << "ls" << "-l", &res, SILENT_STATUS))
if(!runFossil(QStringList() << "ls" << "-l", &res, RUNGLAGS_SILENT_ALL))
return;
bool scan_files = ui->actionViewUnknown->isChecked();
@ -580,8 +580,8 @@ void MainWindow::scanWorkspace()
// If we should not be showing ignored files, fill in the ignored spec
if(!ui->actionViewIgnored->isChecked())
{
// QDir expects multiple specs being separated by a semicolor
ignore = settings.ignoreGlob.replace(',',';');
// QDir expects multiple specs being separated by a semicolon
ignore = settings.Mappings[FUEL_SETTING_IGNORE_GLOB].Value.toString().replace(',',';');
}
scanDirectory(all_files, wkdir, wkdir, ignore);
@ -832,7 +832,7 @@ MainWindow::RepoStatus MainWindow::getRepoStatus()
// We need to determine the reason why fossil has failed
// so we delay processing of the exit_code
if(!runFossilRaw(QStringList() << "info", &res, &exit_code, SILENT_STATUS))
if(!runFossilRaw(QStringList() << "info", &res, &exit_code, RUNGLAGS_SILENT_ALL))
return REPO_NOT_FOUND;
bool run_ok = exit_code == EXIT_SUCCESS;
@ -888,10 +888,10 @@ void MainWindow::on_actionClearLog_triggered()
}
//------------------------------------------------------------------------------
bool MainWindow::runFossil(const QStringList &args, QStringList *output, bool silent, bool detached)
bool MainWindow::runFossil(const QStringList &args, QStringList *output, int runFlags)
{
int exit_code = EXIT_FAILURE;
if(!runFossilRaw(args, output, &exit_code, silent, detached))
if(!runFossilRaw(args, output, &exit_code, runFlags))
return false;
return exit_code == EXIT_SUCCESS;
@ -913,11 +913,15 @@ static QString ParseFossilQuery(QString line)
}
//------------------------------------------------------------------------------
// Run fossil. Returns true if execution was succesfull regardless if fossil
// Run fossil. Returns true if execution was successful regardless if fossil
// issued an error
bool MainWindow::runFossilRaw(const QStringList &args, QStringList *output, int *exitCode, bool silent, bool detached)
bool MainWindow::runFossilRaw(const QStringList &args, QStringList *output, int *exitCode, int runFlags)
{
if(!silent)
bool silent_input = (runFlags & RUNGLAGS_SILENT_INPUT) != 0;
bool silent_output = (runFlags & RUNGLAGS_SILENT_OUTPUT) != 0;
bool detached = (runFlags & RUNGLAGS_DETACHED) != 0;
if(!silent_input)
log("> fossil "+args.join(" ")+"\n");
QString wkdir = getCurrentWorkspace();
@ -985,7 +989,7 @@ bool MainWindow::runFossilRaw(const QStringList &args, QStringList *output, int
int have_yna_query = last_line.toLower().indexOf("a=always/y/n")!=-1 || last_line.toLower().indexOf("yes/no/all")!=-1;
bool have_query = ends_qmark && (have_yn_query || have_yna_query);
// Flush only the unneccessary part of the buffer to the log
// Flush only the unnecessary part of the buffer to the log
QStringList log_lines = buffer.left(last_line_start).split(EOL_MARK);
foreach(QString line, log_lines)
{
@ -996,7 +1000,7 @@ bool MainWindow::runFossilRaw(const QStringList &args, QStringList *output, int
if(output)
output->append(line);
if(!silent)
if(!silent_output)
log(line+"\n");
}
@ -1064,8 +1068,9 @@ bool MainWindow::runFossilRaw(const QStringList &args, QStringList *output, int
QString MainWindow::getFossilPath()
{
// Use the user-specified fossil if available
if(!settings.fossilPath.isEmpty())
return QDir::toNativeSeparators(settings.fossilPath);
QString fossil_path = settings.Mappings[FUEL_SETTING_FOSSIL_PATH].Value.toString();
if(!fossil_path.isEmpty())
return QDir::toNativeSeparators(fossil_path);
QString fossil_exe = "fossil";
#ifdef Q_WS_WIN32
@ -1088,7 +1093,7 @@ void MainWindow::loadSettings()
QSettings qsettings(QSettings::UserScope, QCoreApplication::organizationName(), QCoreApplication::applicationName());
if(qsettings.contains("FossilPath"))
settings.fossilPath = qsettings.value("FossilPath").toString();
settings.Mappings[FUEL_SETTING_FOSSIL_PATH].Value = qsettings.value("FossilPath").toString();
int num_wks = qsettings.beginReadArray("Workspaces");
for(int i=0; i<num_wks; ++i)
@ -1142,8 +1147,9 @@ void MainWindow::saveSettings()
QSettings qsettings(QSettings::UserScope, QCoreApplication::organizationName(), QCoreApplication::applicationName());
// If we have a customize fossil path, save it
if(!settings.fossilPath.isEmpty())
qsettings.setValue("FossilPath", settings.fossilPath);
QString fossil_path = settings.Mappings[FUEL_SETTING_FOSSIL_PATH].Value.toString();
if(!fossil_path .isEmpty())
qsettings.setValue("FossilPath", fossil_path);
qsettings.beginWriteArray("Workspaces", workspaceHistory.size());
for(int i=0; i<workspaceHistory.size(); ++i)
@ -1273,7 +1279,7 @@ void MainWindow::getFileViewSelection(QStringList &filenames, int includeMask, b
bool MainWindow::diffFile(QString repoFile)
{
// Run the diff detached
return runFossil(QStringList() << "gdiff" << QuotePath(repoFile), 0, false, true);
return runFossil(QStringList() << "gdiff" << QuotePath(repoFile), 0, RUNGLAGS_DETACHED);
}
//------------------------------------------------------------------------------
@ -1520,7 +1526,7 @@ void MainWindow::on_actionDelete_triggered()
for(int i=0; i<all_files.size(); ++i)
{
QFileInfo fi(getCurrentWorkspace() + QDir::separator() + all_files[i]);
Q_ASSERT(fi.exists());
if(fi.exists())
QFile::remove(fi.filePath());
}
}
@ -1630,7 +1636,7 @@ void MainWindow::on_actionAbout_triggered()
QString fossil_ver;
QStringList res;
if(runFossil(QStringList() << "version", &res, true) && res.length()==1)
if(runFossil(QStringList() << "version", &res, RUNGLAGS_SILENT_ALL) && res.length()==1)
{
int off = res[0].indexOf("version ");
if(off!=-1)
@ -1672,7 +1678,7 @@ void MainWindow::loadFossilSettings()
{
// Also retrieve the fossil global settings
QStringList out;
if(!runFossil(QStringList() << "settings", &out, true))
if(!runFossil(QStringList() << "settings", &out, RUNGLAGS_SILENT_ALL))
return;
QStringMap kv = MakeKeyValues(out);
@ -1680,6 +1686,24 @@ void MainWindow::loadFossilSettings()
for(Settings::mappings_t::iterator it=settings.Mappings.begin(); it!=settings.Mappings.end(); ++it)
{
const QString &name = it.key();
Settings::Setting::SettingType type = it->Type;
// Internal types are handled explicitly
if(type == Settings::Setting::TYPE_INTERNAL)
continue;
// Command types we issue directly on fossil
if(type == Settings::Setting::TYPE_FOSSIL_COMMAND)
{
// Retrieve existing url
QStringList out;
if(runFossil(QStringList() << name, &out, RUNGLAGS_SILENT_ALL) && out.length()==1)
it.value().Value = out[0].trimmed();
continue;
}
// Otherwise it must be a fossil setting
if(!kv.contains(name))
continue;
@ -1688,14 +1712,13 @@ void MainWindow::loadFossilSettings()
{
int i = value.indexOf(" ");
Q_ASSERT(i!=-1);
Q_ASSERT(it.value());
value = value.mid(i).trimmed();
// Remove quotes if any
if(value.length()>=2 && value.at(0)=='\"' && value.at(value.length()-1)=='\"')
value = value.mid(1, value.length()-2);
*it.value() = value;
it.value().Value = value;
}
}
}
@ -1713,39 +1736,36 @@ void MainWindow::on_actionSettings_triggered()
for(Settings::mappings_t::iterator it=settings.Mappings.begin(); it!=settings.Mappings.end(); ++it)
{
const QString &name = it.key();
QString *value = it.value();
Q_ASSERT(value);
Settings::Setting::SettingType type = it.value().Type;
if(value->isEmpty())
runFossil(QStringList() << "unset" << name << "-global");
else
runFossil(QStringList() << "settings" << name << "\"" + *value + "\"" <<"-global");
}
}
// Internal types are handled explicitly
if(type == Settings::Setting::TYPE_INTERNAL)
continue;
//------------------------------------------------------------------------------
void MainWindow::on_actionSyncSettings_triggered()
{
QString current;
// Retrieve existing url
QStringList out;
if(runFossil(QStringList() << "remote-url", &out, true) && out.length()==1)
current = out[0].trimmed();
if(!DialogQueryText(this, tr("Remote URL"), tr("Enter new remote URL:"), current))
return;
QUrl url(current);
if(!url.isValid())
// Command types we issue directly on fossil
if(type == Settings::Setting::TYPE_FOSSIL_COMMAND)
{
QMessageBox::critical(this, tr("Remote URL"), tr("This URL is not valid"), QMessageBox::Ok );
return;
// Run as silent to avoid displaying credentials in the log
runFossil(QStringList() << "remote-url" << QuotePath(it.value().Value.toString()), 0, RUNGLAGS_SILENT_INPUT);
continue;
}
// Run as silent to avoid displaying credentials in the log
runFossil(QStringList() << "remote-url" << QuotePath(url.toString()), 0, true);
}
Q_ASSERT(type == Settings::Setting::TYPE_FOSSIL_GLOBAL || type == Settings::Setting::TYPE_FOSSIL_LOCAL);
QString value = it.value().Value.toString();
QStringList params;
if(value.isEmpty())
params << "unset" << name;
else
params << "settings" << name << "\"" + value + "\"";
if(type == Settings::Setting::TYPE_FOSSIL_GLOBAL)
params << "-global";
runFossil(params);
}
}
//------------------------------------------------------------------------------
void MainWindow::on_actionViewModified_triggered()

View File

@ -124,12 +124,20 @@ public:
private:
typedef QSet<QString> stringset_t;
enum RunFlags
{
RUNFLAGS_NONE = 0<<0,
RUNGLAGS_SILENT_INPUT = 1<<0,
RUNGLAGS_SILENT_OUTPUT = 1<<1,
RUNGLAGS_SILENT_ALL = RUNGLAGS_SILENT_INPUT | RUNGLAGS_SILENT_OUTPUT,
RUNGLAGS_DETACHED = 1<<2
};
private:
bool refresh();
void scanWorkspace();
bool runFossil(const QStringList &args, QStringList *output=0, bool silent=false, bool detached=false);
bool runFossilRaw(const QStringList &args, QStringList *output=0, int *exitCode=0, bool silent=false, bool detached=false);
bool runFossil(const QStringList &args, QStringList *output=0, int runFlags=RUNFLAGS_NONE);
bool runFossilRaw(const QStringList &args, QStringList *output=0, int *exitCode=0, int runFlags=RUNFLAGS_NONE);
void loadSettings();
void saveSettings();
const QString &getCurrentWorkspace();
@ -197,7 +205,6 @@ private slots:
void on_actionAbout_triggered();
void on_actionUpdate_triggered();
void on_actionSettings_triggered();
void on_actionSyncSettings_triggered();
void on_actionViewUnchanged_triggered();
void on_actionViewModified_triggered();
void on_actionViewUnknown_triggered();
@ -215,6 +222,7 @@ private:
MAX_RECENT=5
};
Ui::MainWindow *ui;
QStandardItemModel repoFileModel;
QStandardItemModel repoDirModel;
@ -241,3 +249,4 @@ private:
};
#endif // MAINWINDOW_H

View File

@ -134,7 +134,6 @@
<addaction name="actionOpenRepository"/>
<addaction name="actionCloseRepository"/>
<addaction name="separator"/>
<addaction name="actionSyncSettings"/>
<addaction name="actionSettings"/>
<addaction name="separator"/>
<addaction name="separator"/>
@ -519,17 +518,6 @@
<string>Set application preferences</string>
</property>
</action>
<action name="actionSyncSettings">
<property name="text">
<string>Fossil Settings...</string>
</property>
<property name="toolTip">
<string>Set remote synchronization settings</string>
</property>
<property name="statusTip">
<string>Set remote synchronization settings</string>
</property>
</action>
<action name="actionViewModified">
<property name="checkable">
<bool>true</bool>

View File

@ -29,10 +29,11 @@ SettingsDialog::SettingsDialog(QWidget *parent, Settings &_settings) :
settings(&_settings)
{
ui->setupUi(this);
ui->lineFossilPath->setText(settings->fossilPath);
ui->lineGDiffCommand->setText(settings->gDiffCommand);
ui->lineGMergeCommand->setText(settings->gMergeCommand);
ui->lineIgnore->setText(settings->ignoreGlob);
ui->lineFossilPath->setText(QDir::toNativeSeparators(settings->Mappings[FUEL_SETTING_FOSSIL_PATH].Value.toString()));
ui->lineGDiffCommand->setText(QDir::toNativeSeparators(settings->Mappings[FUEL_SETTING_GDIFF_CMD].Value.toString()));
ui->lineGMergeCommand->setText(QDir::toNativeSeparators(settings->Mappings[FUEL_SETTING_GMERGE_CMD].Value.toString()));
ui->lineIgnore->setText(settings->Mappings[FUEL_SETTING_IGNORE_GLOB].Value.toString());
ui->lineRemoteURL->setText(settings->Mappings[FUEL_SETTING_REMOTE_URL].Value.toString());
}
//-----------------------------------------------------------------------------
@ -51,17 +52,18 @@ bool SettingsDialog::run(QWidget *parent, Settings &settings)
//-----------------------------------------------------------------------------
void SettingsDialog::on_buttonBox_accepted()
{
settings->fossilPath = ui->lineFossilPath->text();
settings->gDiffCommand = ui->lineGDiffCommand->text();
settings->gMergeCommand = ui->lineGMergeCommand->text();
settings->ignoreGlob = ui->lineIgnore->text();
settings->Mappings[FUEL_SETTING_FOSSIL_PATH].Value = QDir::fromNativeSeparators(ui->lineFossilPath->text());
settings->Mappings[FUEL_SETTING_GDIFF_CMD].Value = QDir::fromNativeSeparators(ui->lineGDiffCommand->text());
settings->Mappings[FUEL_SETTING_GMERGE_CMD].Value = QDir::fromNativeSeparators(ui->lineGMergeCommand->text());
settings->Mappings[FUEL_SETTING_IGNORE_GLOB].Value = ui->lineIgnore->text();
settings->Mappings[FUEL_SETTING_REMOTE_URL].Value = ui->lineRemoteURL->text();
}
//-----------------------------------------------------------------------------
void SettingsDialog::on_btnSelectFossil_clicked()
{
QString path = SelectExe(this, tr("Fossil executable"));
if(!path.isEmpty())
ui->lineFossilPath->setText(path);
ui->lineFossilPath->setText(QDir::toNativeSeparators(path));
}
//-----------------------------------------------------------------------------
@ -69,7 +71,7 @@ void SettingsDialog::on_btnSelectFossilGDiff_clicked()
{
QString path = SelectExe(this, tr("Graphical Diff application"));
if(!path.isEmpty())
ui->lineGDiffCommand->setText(path);
ui->lineGDiffCommand->setText(QDir::toNativeSeparators(path));
}
//-----------------------------------------------------------------------------
@ -77,5 +79,5 @@ void SettingsDialog::on_btnSelectGMerge_clicked()
{
QString path = SelectExe(this, tr("Graphical Merge application"));
if(!path.isEmpty())
ui->lineGMergeCommand->setText(path);
ui->lineGMergeCommand->setText(QDir::toNativeSeparators(path));
}

View File

@ -3,26 +3,46 @@
#include <QDialog>
#include <QMap>
#include <QVariant>
namespace Ui {
class SettingsDialog;
}
#define FUEL_SETTING_FOSSIL_PATH "FossilPath"
#define FUEL_SETTING_GDIFF_CMD "gdiff-command"
#define FUEL_SETTING_GMERGE_CMD "gmerge-command"
#define FUEL_SETTING_IGNORE_GLOB "ignore-glob"
#define FUEL_SETTING_REMOTE_URL "remote-url"
struct Settings
{
QString fossilPath;
QString gDiffCommand;
QString gMergeCommand;
QString ignoreGlob;
struct Setting
{
enum SettingType
{
TYPE_INTERNAL,
TYPE_FOSSIL_GLOBAL,
TYPE_FOSSIL_LOCAL,
TYPE_FOSSIL_COMMAND,
};
typedef QMap<QString, QString *> mappings_t;
Setting(QVariant value=QVariant(), SettingType type=TYPE_INTERNAL) : Value(value), Type(type)
{}
QVariant Value;
SettingType Type;
};
typedef QMap<QString, Setting> mappings_t;
mappings_t Mappings;
Settings()
{
Mappings.insert("gdiff-command", &gDiffCommand);
Mappings.insert("gmerge-command", &gMergeCommand);
Mappings.insert("ignore-glob", &ignoreGlob);
Mappings[FUEL_SETTING_FOSSIL_PATH] = Setting();
Mappings[FUEL_SETTING_GDIFF_CMD] = Setting("", Setting::TYPE_FOSSIL_GLOBAL);
Mappings[FUEL_SETTING_GMERGE_CMD] = Setting("", Setting::TYPE_FOSSIL_GLOBAL);
Mappings[FUEL_SETTING_IGNORE_GLOB] = Setting("", Setting::TYPE_FOSSIL_LOCAL);
Mappings[FUEL_SETTING_REMOTE_URL] = Setting("off", Setting::TYPE_FOSSIL_COMMAND);
}
};

View File

@ -10,7 +10,7 @@
<x>0</x>
<y>0</y>
<width>544</width>
<height>160</height>
<height>186</height>
</rect>
</property>
<property name="windowTitle">
@ -111,7 +111,17 @@
<item row="3" column="1">
<widget class="QLineEdit" name="lineIgnore"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Remote Url</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="lineRemoteURL"/>
</item>
<item row="5" column="1">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
@ -122,12 +132,14 @@
</widget>
</item>
</layout>
<zorder>buttonBox</zorder>
<zorder>label_2</zorder>
<zorder>label_3</zorder>
<zorder>label</zorder>
<zorder>label_4</zorder>
<zorder>lineIgnore</zorder>
<zorder>buttonBox</zorder>
<zorder>lineRemoteURL</zorder>
<zorder>label_5</zorder>
</widget>
<resources/>
<connections>

View File

@ -1,17 +1,17 @@
C Removed\sunused\sRepoDialog
D 2011-10-19T16:24:42.452
C Integrated\sall\sfossil/fuel\soptions\sinto\sthe\sSettings\sdialog\nrunFossil\snow\suses\sa\sbitfield\sto\scontrol\sexecution\soptions\nSettings\smanagement\snow\ssucks\sless,\s(but\sstill\senough\ssuckage\sremains)\n\n
D 2011-10-19T16:30:12.635
F CommitDialog.cpp 8965e52d077c300cf1acb1b16fb2dcca5c7070f8
F CommitDialog.h a9596d99865cf312b419d01d51334ffc916f5508
F CommitDialog.ui 5067623f6af6f5a42c87df903278e383e945e154
F FileActionDialog.cpp fcaebf9986f789b3440d5390b3458ad5f86fe0c8
F FileActionDialog.h 15db1650b3a13d70bc338371e4c033c66e3b79ce
F FileActionDialog.ui c63644428579741aeb5fa052e237ba799ced9ad7
F MainWindow.cpp 7d9f8914b3a16e3ab72e255f40b4c13f4e32cca3
F MainWindow.h 632c5ba933ed77bf9dbe144224e1e6c16fec83e2
F MainWindow.ui c00f9d35aaf659fafee25a5504bd23b0b2ec4eb5
F SettingsDialog.cpp 4e8d12cd19c19590c68eaa3516441d21d08f0ee6
F SettingsDialog.h c2a7828466a5459d8c08a759f0ddf3e368357e80
F SettingsDialog.ui 292eea79612f0daa48b67436fcf812f48ff5af54
F MainWindow.cpp 35de92266b4051a687cb0cd400dc668f1890a8ce
F MainWindow.h 793882064fc9572744f2016ed559f7b9d26632ec
F MainWindow.ui 7f9e5cda55cffd5da8c01de7729a1806126c0d6b
F SettingsDialog.cpp a386f03a13115b8179361344c830bcdb2c319476
F SettingsDialog.h 079e869f60b37feac78198afe0dfd5b75eee9add
F SettingsDialog.ui 8e5b742e889665273d11980959f390ec98dacc06
F fuel.pro b304761003917ba0790be1b62d537642a7e40adb
F fuel.rc 8e9ac966f283102c11a77cd7f936cdc09e09bd79
F icons/Address\sBook-01.png ef2cec80ea5a559b72e8be4a344a1869fe69cbd8
@ -172,7 +172,7 @@ F installer/fuel.iss 13b6a938bcdf273cbd3649d2549887baa1577214
F installer/license.txt 4cc77b90af91e615a64ae04893fdffa7939db84c
F main.cpp f67a9b5c9ca0b634b19ef08e7136032372d37f93
F resources.qrc e98383ed205f4e37100c60057e0129c3b86dea53
P a2cba45b7a250bb1ad3ba4beb3a3a98dc7566ce0
R faf331f106f12f44e5fa947482005b9e
P fb85ae054f85e81e64e9d534fe502959f7f1fa2e
R 5776c676c29c7c55718b710700e50136
U kostas
Z c4bc02d7e2163cc0f4371f837a7d7e0f
Z 50978861702a0b2ec83192ce7566f1c8

View File

@ -1 +1 @@
fb85ae054f85e81e64e9d534fe502959f7f1fa2e
91c5a65b7e4ca4801a6d7632abd7982d2063a1f3