From fa29d4ba1143ad07f3f3d7ffa5f0e851f4dd6381 Mon Sep 17 00:00:00 2001 From: lordmulder Date: Sat, 14 Mar 2015 14:01:50 +0100 Subject: [PATCH] Moved binaries checking code into a separate thread + show spinner while application is initializing. --- res/images/spinner.gif | Bin 0 -> 43176 bytes res/resources.qrc | 1 + src/thread_binaries.cpp | 193 +++++++++++++++++++++++++ src/thread_binaries.h | 64 ++++++++ src/version.h | 2 +- src/win_main.cpp | 145 +++++++++---------- src/win_main.h | 6 +- x264_launcher_MSVC2013.vcxproj | 10 ++ x264_launcher_MSVC2013.vcxproj.filters | 9 ++ 9 files changed, 346 insertions(+), 84 deletions(-) create mode 100644 res/images/spinner.gif create mode 100644 src/thread_binaries.cpp create mode 100644 src/thread_binaries.h diff --git a/res/images/spinner.gif b/res/images/spinner.gif new file mode 100644 index 0000000000000000000000000000000000000000..0d3401fb1a87a19194a62647eea98a4dafe556a4 GIT binary patch literal 43176 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/loading.gif images/movie.png images/python.png + images/spinner.gif images/update.png images/update_wizard.png images/x264.png diff --git a/src/thread_binaries.cpp b/src/thread_binaries.cpp new file mode 100644 index 0000000..eb4b40a --- /dev/null +++ b/src/thread_binaries.cpp @@ -0,0 +1,193 @@ +/////////////////////////////////////////////////////////////////////////////// +// Simple x264 Launcher +// Copyright (C) 2004-2015 LoRd_MuldeR +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// http://www.gnu.org/licenses/gpl-2.0.txt +/////////////////////////////////////////////////////////////////////////////// + +#include "thread_binaries.h" + +#include +#include +#include +#include +#include +#include +#include + +//Internal +#include "global.h" +#include "model_sysinfo.h" +#include "win_updater.h" +#include "binaries.h" + +//MUtils +#include +#include + +//Static +QMutex BinariesCheckThread::m_binLock; +QScopedPointer BinariesCheckThread::m_binPath[MAX_BINARIES]; + +//Whatever +#define NEXT(X) ((*reinterpret_cast(&(X)))++) + +//------------------------------------- +// External API +//------------------------------------- + +bool BinariesCheckThread::check(SysinfoModel *sysinfo) +{ + QMutexLocker lock(&m_binLock); + + QEventLoop loop; + BinariesCheckThread thread(sysinfo); + + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + + connect(&thread, SIGNAL(finished()), &loop, SLOT(quit())); + connect(&thread, SIGNAL(terminated()), &loop, SLOT(quit())); + + thread.start(); + QTimer::singleShot(30000, &loop, SLOT(quit())); + + qDebug("Binaries checker thread has been created, please wait..."); + loop.exec(QEventLoop::ExcludeUserInputEvents); + qDebug("Binaries checker thread finished."); + + QApplication::restoreOverrideCursor(); + + if(!thread.wait(1000)) + { + qWarning("Binaries checker thread encountered timeout -> probably deadlock!"); + thread.terminate(); + thread.wait(); + return false; + } + + if(thread.getException()) + { + qWarning("Binaries checker thread encountered an exception !!!"); + return false; + } + + return thread.getSuccess(); +} + +//------------------------------------- +// Thread class +//------------------------------------- + +BinariesCheckThread::BinariesCheckThread(const SysinfoModel *const sysinfo) +: + m_sysinfo(sysinfo) +{ + m_success = m_exception = false; +} + +BinariesCheckThread::~BinariesCheckThread(void) +{ +} + +void BinariesCheckThread::run(void) +{ + m_success = m_exception = false; + checkBinaries1(m_success, m_sysinfo, &m_exception); +} + +void BinariesCheckThread::checkBinaries1(volatile bool &success, const SysinfoModel *const sysinfo, volatile bool *exception) +{ + __try + { + checkBinaries2(success, sysinfo, exception); + } + __except(1) + { + *exception = true; + qWarning("Unhandled exception error in binaries checker thread !!!"); + } +} + +void BinariesCheckThread::checkBinaries2(volatile bool &success, const SysinfoModel *const sysinfo, volatile bool *exception) +{ + try + { + return checkBinaries3(success, sysinfo); + } + catch(...) + { + *exception = true; + qWarning("Binaries checker initializdation raised an C++ exception!"); + } +} + +void BinariesCheckThread::checkBinaries3(volatile bool &success, const SysinfoModel *const sysinfo) +{ + success = true; + + //Create list of all required binary files + QStringList binFiles; + for(OptionsModel::EncArch arch = OptionsModel::EncArch_x32; arch <= OptionsModel::EncArch_x64; NEXT(arch)) + { + for(OptionsModel::EncType encdr = OptionsModel::EncType_X264; encdr <= OptionsModel::EncType_X265; NEXT(encdr)) + { + for(OptionsModel::EncVariant varnt = OptionsModel::EncVariant_LoBit; varnt <= OptionsModel::EncVariant_HiBit; NEXT(varnt)) + { + binFiles << ENC_BINARY(sysinfo, encdr, arch, varnt); + } + } + binFiles << AVS_BINARY(sysinfo, arch == OptionsModel::EncArch_x64); + binFiles << CHK_BINARY(sysinfo, arch == OptionsModel::EncArch_x64); + } + for(size_t i = 0; UpdaterDialog::BINARIES[i].name; i++) + { + if(UpdaterDialog::BINARIES[i].exec) + { + binFiles << QString("%1/toolset/common/%2").arg(sysinfo->getAppPath(), QString::fromLatin1(UpdaterDialog::BINARIES[i].name)); + } + } + + //Actually validate the binaries + size_t currentFile = 0; + for(QStringList::ConstIterator iter = binFiles.constBegin(); iter != binFiles.constEnd(); iter++) + { + QScopedPointer file(new QFile(*iter)); + qDebug("%s", MUTILS_UTF8(file->fileName())); + + if(file->open(QIODevice::ReadOnly)) + { + if(!MUtils::OS::is_executable_file(file->fileName())) + { + success = false; + qWarning("Required tool does NOT seem to be a valid Win32/Win64 binary:\n%s\n", MUTILS_UTF8(file->fileName())); + return; + } + if(currentFile < MAX_BINARIES) + { + m_binPath[currentFile++].reset(file.take()); + continue; + } + qFatal("Current binary file exceeds max. number of binaries!"); + } + else + { + success = false; + qWarning("Required tool could not be found or access denied:\n%s\n", MUTILS_UTF8(file->fileName())); + return; + } + } +} diff --git a/src/thread_binaries.h b/src/thread_binaries.h new file mode 100644 index 0000000..937a9da --- /dev/null +++ b/src/thread_binaries.h @@ -0,0 +1,64 @@ +/////////////////////////////////////////////////////////////////////////////// +// Simple x264 Launcher +// Copyright (C) 2004-2015 LoRd_MuldeR +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// http://www.gnu.org/licenses/gpl-2.0.txt +/////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include +#include + +class QLibrary; +class SysinfoModel; +class QFile; + +class BinariesCheckThread : public QThread +{ + Q_OBJECT + +public: + static bool check(SysinfoModel *sysinfo); + +protected: + BinariesCheckThread(const SysinfoModel *const sysinfo); + ~BinariesCheckThread(void); + + int getSuccess(void) { return m_success; } + bool getException(void) { return m_exception; } + +private slots: + void start(Priority priority = InheritPriority) { QThread::start(priority); } + +private: + volatile bool m_exception; + volatile bool m_success; + const SysinfoModel *const m_sysinfo; + + static const size_t MAX_BINARIES = 16; + static QMutex m_binLock; + static QScopedPointer m_binPath[MAX_BINARIES]; + + //Entry point + virtual void run(void); + + //Functions + static void checkBinaries1(volatile bool &success, const SysinfoModel *const sysinfo, volatile bool *exception); + static void checkBinaries2(volatile bool &success, const SysinfoModel *const sysinfo, volatile bool *exception); + static void checkBinaries3(volatile bool &success, const SysinfoModel *const sysinfo); +}; diff --git a/src/version.h b/src/version.h index 666f0c1..f197345 100644 --- a/src/version.h +++ b/src/version.h @@ -26,7 +26,7 @@ #define VER_X264_MAJOR 2 #define VER_X264_MINOR 5 #define VER_X264_PATCH 0 -#define VER_X264_BUILD 934 +#define VER_X264_BUILD 940 #define VER_X264_PORTABLE_EDITION (0) diff --git a/src/win_main.cpp b/src/win_main.cpp index 8b2bae2..2134051 100644 --- a/src/win_main.cpp +++ b/src/win_main.cpp @@ -33,6 +33,7 @@ #include "model_preferences.h" #include "model_recently.h" #include "thread_avisynth.h" +#include "thread_binaries.h" #include "thread_vapoursynth.h" #include "thread_encode.h" #include "thread_ipc_recv.h" @@ -70,6 +71,7 @@ #include #include #include +#include #include @@ -87,7 +89,6 @@ static const int vsynth_rev = 24; #define SET_TEXT_COLOR(WIDGET,COLOR) do { QPalette _palette = WIDGET->palette(); _palette.setColor(QPalette::WindowText, (COLOR)); _palette.setColor(QPalette::Text, (COLOR)); WIDGET->setPalette(_palette); } while(0) #define LINK(URL) (QString("%1").arg((URL))) #define INIT_ERROR_EXIT() do { close(); qApp->exit(-1); return; } while(0) -#define NEXT(X) ((*reinterpret_cast(&(X)))++) #define SETUP_WEBLINK(OBJ, URL) do { (OBJ)->setData(QVariant(QUrl(URL))); connect((OBJ), SIGNAL(triggered()), this, SLOT(showWebLink())); } while(0) #define APP_IS_READY (m_initialized && (!m_fileTimer->isActive()) && (QApplication::activeModalWidget() == NULL)) #define ENSURE_APP_IS_READY() do { if(!APP_IS_READY) { MUtils::Sound::beep(MUtils::Sound::BEEP_WRN); qWarning("Cannot perfrom this action at this time!"); return; } } while(0) @@ -225,7 +226,7 @@ MainWindow::MainWindow(const MUtils::CPUFetaures::cpu_info_t &cpuFeatures, MUtil SETUP_WEBLINK(ui->actionWebAvisynthPlus, "http://www.avs-plus.net/"); SETUP_WEBLINK(ui->actionWebVapourSynth, "http://www.vapoursynth.com/"); SETUP_WEBLINK(ui->actionWebVapourSynthDocs, "http://www.vapoursynth.com/doc/"); - SETUP_WEBLINK(ui->actionOnlineDocX264, "http://mewiki.project357.com/wiki/X264_Settings"); + SETUP_WEBLINK(ui->actionOnlineDocX264, "http://en.wikibooks.org/wiki/MeGUI/x264_Settings"); //http://mewiki.project357.com/wiki/X264_Settings SETUP_WEBLINK(ui->actionOnlineDocX265, "http://x265.readthedocs.org/en/default/"); SETUP_WEBLINK(ui->actionWebBluRay, "http://www.x264bluray.com/"); SETUP_WEBLINK(ui->actionWebAvsWiki, "http://avisynth.nl/index.php/Main_Page#Usage"); @@ -233,14 +234,28 @@ MainWindow::MainWindow(const MUtils::CPUFetaures::cpu_info_t &cpuFeatures, MUtil SETUP_WEBLINK(ui->actionWebSecret, "http://www.youtube.com/watch_popup?v=AXIeHY-OYNI"); //Create floating label - m_label.reset(new QLabel(ui->jobsView->viewport())); - m_label->setText(tr("No job created yet. Please click the 'Add New Job' button!")); - m_label->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); - SET_TEXT_COLOR(m_label, Qt::darkGray); - SET_FONT_BOLD(m_label, true); - m_label->setVisible(true); - m_label->setContextMenuPolicy(Qt::ActionsContextMenu); - m_label->addActions(ui->jobsView->actions()); + m_label[0].reset(new QLabel(ui->jobsView->viewport())); + m_label[1].reset(new QLabel(ui->logView->viewport())); + if(!m_label[0].isNull()) + { + m_label[0]->setText(tr("No job created yet. Please click the 'Add New Job' button!")); + m_label[0]->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); + SET_TEXT_COLOR(m_label[0], Qt::darkGray); + SET_FONT_BOLD(m_label[0], true); + m_label[0]->setVisible(true); + m_label[0]->setContextMenuPolicy(Qt::ActionsContextMenu); + m_label[0]->addActions(ui->jobsView->actions()); + } + if(!m_label[1].isNull()) + { + m_animation.reset(new QMovie(":/images/spinner.gif")); + m_label[1]->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); + if(!m_animation.isNull()) + { + m_label[1]->setMovie(m_animation.data()); + m_animation->start(); + } + } connect(ui->splitter, SIGNAL(splitterMoved(int, int)), this, SLOT(updateLabelPos())); updateLabelPos(); @@ -277,12 +292,6 @@ MainWindow::~MainWindow(void) { OptionsModel::saveTemplate(m_options.data(), QString::fromLatin1(tpl_last)); - while(!m_toolsList->isEmpty()) - { - QFile *temp = m_toolsList->takeFirst(); - MUTILS_DELETE(temp); - } - if(!m_ipcThread.isNull()) { m_ipcThread->stop(); @@ -374,7 +383,7 @@ void MainWindow::deleteButtonPressed(void) ENSURE_APP_IS_READY(); m_jobList->deleteJob(ui->jobsView->currentIndex()); - m_label->setVisible(m_jobList->rowCount(QModelIndex()) == 0); + m_label[0]->setVisible(m_jobList->rowCount(QModelIndex()) == 0); } /* @@ -765,60 +774,17 @@ void MainWindow::init(void) updateLabelPos(); const MUtils::OS::ArgumentMap &arguments = MUtils::OS::arguments(); + qApp->processEvents(QEventLoop::ExcludeUserInputEvents); //--------------------------------------- // Check required binaries //--------------------------------------- - - QStringList binFiles; - for(OptionsModel::EncArch arch = OptionsModel::EncArch_x32; arch <= OptionsModel::EncArch_x64; NEXT(arch)) - { - for(OptionsModel::EncType encdr = OptionsModel::EncType_X264; encdr <= OptionsModel::EncType_X265; NEXT(encdr)) - { - for(OptionsModel::EncVariant varnt = OptionsModel::EncVariant_LoBit; varnt <= OptionsModel::EncVariant_HiBit; NEXT(varnt)) - { - binFiles << ENC_BINARY(m_sysinfo.data(), encdr, arch, varnt); - } - } - binFiles << AVS_BINARY(m_sysinfo.data(), arch == OptionsModel::EncArch_x64); - binFiles << CHK_BINARY(m_sysinfo.data(), arch == OptionsModel::EncArch_x64); - } - for(size_t i = 0; UpdaterDialog::BINARIES[i].name; i++) - { - if(UpdaterDialog::BINARIES[i].exec) - { - binFiles << QString("%1/toolset/common/%2").arg(m_sysinfo->getAppPath(), QString::fromLatin1(UpdaterDialog::BINARIES[i].name)); - } - } qDebug("[Validating binaries]"); - for(QStringList::ConstIterator iter = binFiles.constBegin(); iter != binFiles.constEnd(); iter++) + if(!BinariesCheckThread::check(m_sysinfo.data())) { - qApp->processEvents(QEventLoop::ExcludeUserInputEvents); - QFile *file = new QFile(*iter); - qDebug("%s", file->fileName().toLatin1().constData()); - if(file->open(QIODevice::ReadOnly)) - { - if(!MUtils::OS::is_executable_file(file->fileName())) - { - QMessageBox::critical(this, tr("Invalid File!"), tr("At least on required tool is not a valid Win32 or Win64 binary:
%1

Please re-install the program in order to fix the problem!
").arg(QDir::toNativeSeparators(file->fileName())).replace("-", "−")); - qFatal(QString("Binary is invalid: %1").arg(file->fileName()).toLatin1().constData()); - MUTILS_DELETE(file); - INIT_ERROR_EXIT(); - } - if(m_toolsList.isNull()) - { - m_toolsList.reset(new QFileList()); - } - m_toolsList->append(file); - } - else - { - QMessageBox::critical(this, tr("File Not Found!"), tr("At least on required tool could not be found:
%1

Please re-install the program in order to fix the problem!
").arg(QDir::toNativeSeparators(file->fileName())).replace("-", "−")); - qFatal(QString("Binary not found: %1/toolset/%2").arg(m_sysinfo->getAppPath(), file->fileName()).toLatin1().constData()); - MUTILS_DELETE(file); - INIT_ERROR_EXIT(); - } + QMessageBox::critical(this, tr("Invalid File!"), tr("At least on required tool is missing or is not a valid Win32/Win64 binary.
Please re-install the program in order to fix the problem!
").replace("-", "−")); + qFatal("At least on required tool is missing or is not a valid Win32/Win64 binary!"); } qDebug(" "); @@ -851,6 +817,8 @@ void MainWindow::init(void) if(rnd != val) INIT_ERROR_EXIT(); } + qApp->processEvents(QEventLoop::ExcludeUserInputEvents); + //--------------------------------------- // Check CPU capabilities //--------------------------------------- @@ -883,6 +851,8 @@ void MainWindow::init(void) m_preferences->setAbortOnTimeout(false); } + qApp->processEvents(QEventLoop::ExcludeUserInputEvents); + //--------------------------------------- // Check Avisynth support //--------------------------------------- @@ -942,6 +912,17 @@ void MainWindow::init(void) qDebug(" "); } + //--------------------------------------- + // Create the IPC listener thread + //--------------------------------------- + + if(m_ipcChannel) + { + m_ipcThread.reset(new IPCThread_Recv(m_ipcChannel)); + connect(m_ipcThread.data(), SIGNAL(receivedCommand(int,QStringList,quint32)), this, SLOT(handleCommand(int,QStringList,quint32)), Qt::QueuedConnection); + m_ipcThread->start(); + } + //--------------------------------------- // Finish initialization //--------------------------------------- @@ -955,6 +936,16 @@ void MainWindow::init(void) //Update flag m_initialized = true; + //Hide the spinner animation + if(!m_label[1].isNull()) + { + if(!m_animation.isNull()) + { + m_animation->stop(); + } + m_label[1]->setVisible(false); + } + //--------------------------------------- // Check for Expiration //--------------------------------------- @@ -1007,21 +998,10 @@ void MainWindow::init(void) } } - //--------------------------------------- - // Create the IPC listener thread - //--------------------------------------- - - if(m_ipcChannel) - { - m_ipcThread.reset(new IPCThread_Recv(m_ipcChannel)); - connect(m_ipcThread.data(), SIGNAL(receivedCommand(int,QStringList,quint32)), this, SLOT(handleCommand(int,QStringList,quint32)), Qt::QueuedConnection); - m_ipcThread->start(); - } - //Load queued jobs if(m_jobList->loadQueuedJobs(m_sysinfo.data()) > 0) { - m_label->setVisible(m_jobList->rowCount(QModelIndex()) == 0); + m_label[0]->setVisible(m_jobList->rowCount(QModelIndex()) == 0); m_jobList->clearQueuedJobs(); } } @@ -1031,8 +1011,15 @@ void MainWindow::init(void) */ void MainWindow::updateLabelPos(void) { - const QWidget *const viewPort = ui->jobsView->viewport(); - m_label->setGeometry(0, 0, viewPort->width(), viewPort->height()); + for(int i = 0; i < 2; i++) + { + //const QWidget *const viewPort = ui->jobsView->viewport(); + const QWidget *const viewPort = dynamic_cast(m_label[i]->parent()); + if(viewPort) + { + m_label[i]->setGeometry(0, 0, viewPort->width(), viewPort->height()); + } + } } /* @@ -1467,7 +1454,7 @@ bool MainWindow::appendJob(const QString &sourceFileName, const QString &outputF okay = true; } - m_label->setVisible(m_jobList->rowCount(QModelIndex()) == 0); + m_label[0]->setVisible(m_jobList->rowCount(QModelIndex()) == 0); return okay; } diff --git a/src/win_main.h b/src/win_main.h index c9227b3..c022758 100644 --- a/src/win_main.h +++ b/src/win_main.h @@ -66,8 +66,6 @@ public: MainWindow(const MUtils::CPUFetaures::cpu_info_t &cpuFeatures, MUtils::IPCChannel *const ipcChannel); ~MainWindow(void); - typedef QList QFileList; - protected: virtual void closeEvent(QCloseEvent *e); virtual void showEvent(QShowEvent *e); @@ -80,7 +78,8 @@ private: MUtils::IPCChannel *const m_ipcChannel; bool m_initialized; - QScopedPointer m_label; + QScopedPointer m_label[2]; + QScopedPointer m_animation; QScopedPointer m_fileTimer; QScopedPointer m_ipcThread; @@ -94,7 +93,6 @@ private: QScopedPointer m_jobList; QScopedPointer m_options; QScopedPointer m_pendingFiles; - QScopedPointer m_toolsList; QScopedPointer m_sysinfo; QScopedPointer m_preferences; diff --git a/x264_launcher_MSVC2013.vcxproj b/x264_launcher_MSVC2013.vcxproj index 906f785..b14d0b1 100644 --- a/x264_launcher_MSVC2013.vcxproj +++ b/x264_launcher_MSVC2013.vcxproj @@ -274,6 +274,14 @@ copy /Y "$(QTDIR)\plugins\imageformats\qgif4.dll" "$(TargetDir)\imageformats" $(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp;%(Outputs) $(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp;%(Outputs) + + "$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp" "%(FullPath)" + "$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp" "%(FullPath)" + MOC "$(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp" + MOC "$(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp" + $(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp;%(Outputs) + $(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp;%(Outputs) + @@ -432,6 +440,7 @@ copy /Y "$(QTDIR)\plugins\imageformats\qgif4.dll" "$(TargetDir)\imageformats" + @@ -451,6 +460,7 @@ copy /Y "$(QTDIR)\plugins\imageformats\qgif4.dll" "$(TargetDir)\imageformats" + diff --git a/x264_launcher_MSVC2013.vcxproj.filters b/x264_launcher_MSVC2013.vcxproj.filters index 61414b7..e37c01c 100644 --- a/x264_launcher_MSVC2013.vcxproj.filters +++ b/x264_launcher_MSVC2013.vcxproj.filters @@ -111,6 +111,9 @@ Generated Files + + Header Files + @@ -260,6 +263,12 @@ Generated Files + + Source Files + + + Generated Files +