From 039bb72499b6934850870f1428f122ac5bd1e39f Mon Sep 17 00:00:00 2001 From: Raphael Dumusc Date: Wed, 22 Jun 2016 15:27:27 +0200 Subject: [PATCH 1/4] Launcher: reuse image caching mechanism from the old Dock [DISCL-368] --- apps/Launcher/qml/FileBrowser.qml | 1 + doc/Changelog.md | 2 ++ tide/core/thumbnail/ThumbnailProvider.cpp | 29 +++++++++++++++++++++-- tide/core/thumbnail/ThumbnailProvider.h | 15 ++++++++++++ 4 files changed, 45 insertions(+), 2 deletions(-) diff --git a/apps/Launcher/qml/FileBrowser.qml b/apps/Launcher/qml/FileBrowser.qml index 1303eff6..f2dd282f 100644 --- a/apps/Launcher/qml/FileBrowser.qml +++ b/apps/Launcher/qml/FileBrowser.qml @@ -63,6 +63,7 @@ Rectangle { Image { id: thumbnail anchors.fill: parent + cache: false source: "image://thumbnail/" + filePath fillMode: Image.PreserveAspectFit } diff --git a/doc/Changelog.md b/doc/Changelog.md index 61edc2dd..6d83844e 100644 --- a/doc/Changelog.md +++ b/doc/Changelog.md @@ -3,6 +3,8 @@ Changelog {#Changelog} # git master (1.1.0) +* [46](https://github.com/BlueBrain/Tide/pull/46): + The Launcher creates and caches file thumbnails more efficiently. * [38](https://github.com/BlueBrain/Tide/pull/38): Fix a segfault that occured when opening grayscale images. * [36](https://github.com/BlueBrain/Tide/pull/36): diff --git a/tide/core/thumbnail/ThumbnailProvider.cpp b/tide/core/thumbnail/ThumbnailProvider.cpp index 8051a2f4..84ccfab9 100644 --- a/tide/core/thumbnail/ThumbnailProvider.cpp +++ b/tide/core/thumbnail/ThumbnailProvider.cpp @@ -43,11 +43,14 @@ #include "ThumbnailGenerator.h" #include "ThumbnailGeneratorFactory.h" +#include #include #include namespace { +const int cacheMaxSize = 200; +const QString cacheModificationDateKey( "lastModificationDate" ); const char* folderImg = "qrc:/img/folder.png"; const char* unknownFileImg = "qrc:/img/unknownfile.png"; } @@ -56,7 +59,9 @@ ThumbnailProvider::ThumbnailProvider( const QSize defaultSize ) : QQuickImageProvider( QQuickImageProvider::Image, QQuickImageProvider::ForceAsynchronousImageLoading ) , _defaultSize( defaultSize ) -{} +{ + _cache.setMaxCost( cacheMaxSize ); +} QImage ThumbnailProvider::requestImage( const QString& filename, QSize* size, const QSize& requestedSize ) @@ -68,12 +73,23 @@ QImage ThumbnailProvider::requestImage( const QString& filename, QSize* size, if( size ) *size = newSize; + if( _isImageInCache( filename )) + return *_cache[filename]; + auto generator = ThumbnailGeneratorFactory::getGenerator( filename, newSize ); const QImage image = generator->generate( filename ); if( !image.isNull( )) + { + // QCache requires a * and takes ownership, a new QImage is required + QImage* cacheImage = new QImage( image ); + cacheImage->setText( cacheModificationDateKey, + QFileInfo( filename ).lastModified().toString( )); + _cache.insert( filename, cacheImage ); return image; + } + // Thumbnail generation failed, return a placeholder const QFileInfo fileInfo( filename ); if( fileInfo.isFile( )) { @@ -81,7 +97,6 @@ QImage ThumbnailProvider::requestImage( const QString& filename, QSize* size, assert( !im.isNull( )); return im; } - if( fileInfo.isDir( )) { static QImage im( folderImg ); @@ -91,3 +106,13 @@ QImage ThumbnailProvider::requestImage( const QString& filename, QSize* size, return image; // Silence compiler warning } + +bool ThumbnailProvider::_isImageInCache( const QString& filename ) const +{ + if( !_cache.contains( filename )) + return false; + + const QFileInfo info( filename ); + return info.lastModified().toString() == + _cache.object( filename )->text( cacheModificationDateKey ); +} diff --git a/tide/core/thumbnail/ThumbnailProvider.h b/tide/core/thumbnail/ThumbnailProvider.h index c87c9348..dd114b2c 100644 --- a/tide/core/thumbnail/ThumbnailProvider.h +++ b/tide/core/thumbnail/ThumbnailProvider.h @@ -42,9 +42,21 @@ #define THUMBNAILPROVIDER_H #include +#include /** * Provide thumbnails for files and folders to the Qml FileBrowser. + * + * The provider maintains an internal cache to speed up the request of + * previously generated images. It also takes care of regenerating the thumbnail + * if the file has been modified since the last request (checking the file + * modification date). + * + * Example of correct usage in Qml: + * Image { + * source: "image://thumbnail/" + filePath + * cache: false + * } */ class ThumbnailProvider : public QQuickImageProvider { @@ -56,6 +68,9 @@ class ThumbnailProvider : public QQuickImageProvider private: const QSize _defaultSize; + QCache _cache; + + bool _isImageInCache( const QString& filename ) const; }; #endif From 4047e6dc4ef6294479dd65e2435f9f9bc04220d8 Mon Sep 17 00:00:00 2001 From: Raphael Dumusc Date: Wed, 22 Jun 2016 15:29:31 +0200 Subject: [PATCH 2/4] Launcher: don't generate thumbnails for large PDFs for more efficiency --- tide/core/thumbnail/PDFThumbnailGenerator.cpp | 19 +++++++++++++++++++ tide/core/thumbnail/PDFThumbnailGenerator.h | 3 +++ 2 files changed, 22 insertions(+) diff --git a/tide/core/thumbnail/PDFThumbnailGenerator.cpp b/tide/core/thumbnail/PDFThumbnailGenerator.cpp index f9a21e71..ccb42a9f 100644 --- a/tide/core/thumbnail/PDFThumbnailGenerator.cpp +++ b/tide/core/thumbnail/PDFThumbnailGenerator.cpp @@ -42,6 +42,15 @@ #include "PDF.h" #include "log.h" +#include + +namespace +{ +const size_t sizeOfMegabyte = 1024 * 1024; +// empirical value used to minimize thumbnail generation time +const qint64 maxPdfPageSize = 2 * sizeOfMegabyte; +} + PDFThumbnailGenerator::PDFThumbnailGenerator( const QSize& size ) : ThumbnailGenerator( size ) { @@ -58,6 +67,9 @@ QImage PDFThumbnailGenerator::generate( const QString& filename ) const return createErrorImage( "pdf" ); } + if( QFileInfo( filename ).size() > maxPdfPageSize * pdf.getPageCount( )) + return _createLargePdfPlaceholder(); + QImage image = pdf.renderToImage( size_ ); if( image.isNull( )) @@ -70,3 +82,10 @@ QImage PDFThumbnailGenerator::generate( const QString& filename ) const addMetadataToImage( image, filename ); return image; } + +QImage PDFThumbnailGenerator::_createLargePdfPlaceholder() const +{ + QImage img = createGradientImage( Qt::darkBlue, Qt::white ); + paintText( img, "LARGE\nPDF" ); + return img; +} diff --git a/tide/core/thumbnail/PDFThumbnailGenerator.h b/tide/core/thumbnail/PDFThumbnailGenerator.h index bbb33b13..b46508e2 100644 --- a/tide/core/thumbnail/PDFThumbnailGenerator.h +++ b/tide/core/thumbnail/PDFThumbnailGenerator.h @@ -48,6 +48,9 @@ class PDFThumbnailGenerator : public ThumbnailGenerator PDFThumbnailGenerator( const QSize& size ); QImage generate( const QString& filename ) const override; + +private: + QImage _createLargePdfPlaceholder() const; }; #endif // PDFTHUMBNAILGENERATOR_H From 7063b60b8df58480cc195d6cdf7719398b2783c7 Mon Sep 17 00:00:00 2001 From: Raphael Dumusc Date: Wed, 22 Jun 2016 16:23:19 +0200 Subject: [PATCH 3/4] Cleanup the thumbnail generator code --- .../thumbnail/DefaultThumbnailGenerator.cpp | 13 ++--- .../thumbnail/DefaultThumbnailGenerator.h | 8 +-- .../thumbnail/FolderThumbnailGenerator.cpp | 58 +++++++------------ .../core/thumbnail/FolderThumbnailGenerator.h | 18 +++--- .../thumbnail/ImageThumbnailGenerator.cpp | 23 +++----- tide/core/thumbnail/ImageThumbnailGenerator.h | 12 ++-- .../thumbnail/MovieThumbnailGenerator.cpp | 9 +-- tide/core/thumbnail/MovieThumbnailGenerator.h | 8 +-- tide/core/thumbnail/PDFThumbnailGenerator.cpp | 5 +- tide/core/thumbnail/PDFThumbnailGenerator.h | 6 +- .../thumbnail/PyramidThumbnailGenerator.cpp | 22 +++---- .../thumbnail/PyramidThumbnailGenerator.h | 4 +- .../thumbnail/StateThumbnailGenerator.cpp | 38 ++++++------ tide/core/thumbnail/StateThumbnailGenerator.h | 12 ++-- tide/core/thumbnail/ThumbnailGenerator.cpp | 48 ++++++++------- tide/core/thumbnail/ThumbnailGenerator.h | 24 ++++---- .../thumbnail/ThumbnailGeneratorFactory.cpp | 55 +++++++----------- .../thumbnail/ThumbnailGeneratorFactory.h | 22 +++---- tide/core/thumbnail/ThumbnailProvider.cpp | 2 + 19 files changed, 168 insertions(+), 219 deletions(-) diff --git a/tide/core/thumbnail/DefaultThumbnailGenerator.cpp b/tide/core/thumbnail/DefaultThumbnailGenerator.cpp index b672deae..ab9c78fa 100644 --- a/tide/core/thumbnail/DefaultThumbnailGenerator.cpp +++ b/tide/core/thumbnail/DefaultThumbnailGenerator.cpp @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2016, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* All rights reserved. */ /* */ @@ -39,15 +39,14 @@ #include "DefaultThumbnailGenerator.h" -DefaultThumbnailGenerator::DefaultThumbnailGenerator(const QSize &size) - : ThumbnailGenerator(size) +DefaultThumbnailGenerator::DefaultThumbnailGenerator( const QSize& size ) + : ThumbnailGenerator( size ) { } -QImage DefaultThumbnailGenerator::generate(const QString& filename) const +QImage DefaultThumbnailGenerator::generate( const QString& ) const { - QImage img = createGradientImage( QColor(Qt::black), QColor(Qt::white) ); - paintText(img, "FILE"); - addMetadataToImage(img, filename); + QImage img = createGradientImage( QColor( Qt::black ), QColor( Qt::white )); + paintText( img, "FILE" ); return img; } diff --git a/tide/core/thumbnail/DefaultThumbnailGenerator.h b/tide/core/thumbnail/DefaultThumbnailGenerator.h index eef53cf8..bd09ced2 100644 --- a/tide/core/thumbnail/DefaultThumbnailGenerator.h +++ b/tide/core/thumbnail/DefaultThumbnailGenerator.h @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2016, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* All rights reserved. */ /* */ @@ -45,9 +45,9 @@ class DefaultThumbnailGenerator : public ThumbnailGenerator { public: - DefaultThumbnailGenerator(const QSize& size); + DefaultThumbnailGenerator( const QSize& size ); - QImage generate(const QString& filename) const override; + QImage generate( const QString& filename ) const final; }; -#endif // DEFAULTTHUMBNAILGENERATOR_H +#endif diff --git a/tide/core/thumbnail/FolderThumbnailGenerator.cpp b/tide/core/thumbnail/FolderThumbnailGenerator.cpp index 7e12e3a0..bb580827 100644 --- a/tide/core/thumbnail/FolderThumbnailGenerator.cpp +++ b/tide/core/thumbnail/FolderThumbnailGenerator.cpp @@ -39,14 +39,14 @@ #include "FolderThumbnailGenerator.h" -#include -#include - +#include "ContentFactory.h" #include "ThumbnailGeneratorFactory.h" #include "ThumbnailGenerator.h" -#include "ContentFactory.h" #include "log.h" +#include +#include + namespace { const int FOLDER_THUMBNAILS_X = 2; @@ -57,39 +57,23 @@ const QString FOLDER_TEXT( "folder" ); FolderThumbnailGenerator::FolderThumbnailGenerator( const QSize& size ) : ThumbnailGenerator( size ) -{ -} +{} QImage FolderThumbnailGenerator::generate( const QString& filename ) const { const QDir dir( filename ); if( dir.exists( )) - return createFolderImage( dir, true ); + return _createFolderImage( dir, true ); put_flog( LOG_ERROR, "invalid directory: %s", filename.toLocal8Bit().constData( )); return createErrorImage( "folder" ); } -QImage -FolderThumbnailGenerator::generatePlaceholderImage( const QDir& dir ) const -{ - QImage img = createGradientImage( Qt::black, Qt::white ); - addMetadataToImage( img, dir.path( )); - return img; -} - -void FolderThumbnailGenerator::addMetadataToImage( QImage& img, - const QString& url ) const -{ - img.setText( "dir", "true" ); - ThumbnailGenerator::addMetadataToImage( img, url ); -} - QVector -FolderThumbnailGenerator::calculatePlacement( int nX, int nY, float padding, - float totalWidth, - float totalHeight ) const +FolderThumbnailGenerator::_calculatePlacement( int nX, int nY, float padding, + float totalWidth, + float totalHeight ) const { const float totalPaddingWidth = padding*(nX+1); const float imageWidth = (1.0f-totalPaddingWidth)/(float)nX; @@ -112,16 +96,16 @@ FolderThumbnailGenerator::calculatePlacement( int nX, int nY, float padding, return rect; } -void FolderThumbnailGenerator::paintThumbnailsMosaic( QImage& img, - const QFileInfoList& - fileList) const +void FolderThumbnailGenerator::_paintThumbnailsMosaic( QImage& img, + const QFileInfoList& + fileList ) const { const int numPreviews = std::min( FOLDER_THUMBNAILS_X*FOLDER_THUMBNAILS_Y, fileList.size( )); if( numPreviews == 0 ) return; - QVector rect = calculatePlacement( FOLDER_THUMBNAILS_X, + QVector rect = _calculatePlacement( FOLDER_THUMBNAILS_X, FOLDER_THUMBNAILS_Y, FOLDER_THUMBNAILS_PADDING, img.size().width(), @@ -135,9 +119,9 @@ void FolderThumbnailGenerator::paintThumbnailsMosaic( QImage& img, QImage thumbnail; // Avoid recursion into subfolders if( QDir( filename ).exists( )) - thumbnail = createFolderImage( QDir( filename ), false ); + thumbnail = _createFolderImage( QDir( filename ), false ); else - thumbnail = ThumbnailGeneratorFactory::getGenerator( filename, size_ )->generate( filename ); + thumbnail = ThumbnailGeneratorFactory::getGenerator( filename, _size )->generate( filename ); painter.drawImage( rect[i], thumbnail ); } @@ -145,15 +129,15 @@ void FolderThumbnailGenerator::paintThumbnailsMosaic( QImage& img, } QImage -FolderThumbnailGenerator::createFolderImage( const QDir& dir, - const bool generateThumbnails ) const +FolderThumbnailGenerator::_createFolderImage( const QDir& dir, + const bool generateThumbnails ) const { - QImage img = generatePlaceholderImage( dir ); + QImage img = createGradientImage( Qt::black, Qt::white ); - const QFileInfoList& fileList = getSupportedFilesInDir( dir ); + const QFileInfoList& fileList = _getSupportedFilesInDir( dir ); if( generateThumbnails && fileList.size() > 0 ) - paintThumbnailsMosaic(img, fileList); + _paintThumbnailsMosaic(img, fileList); else paintText( img, FOLDER_TEXT ); @@ -161,7 +145,7 @@ FolderThumbnailGenerator::createFolderImage( const QDir& dir, } QFileInfoList -FolderThumbnailGenerator::getSupportedFilesInDir( QDir dir ) const +FolderThumbnailGenerator::_getSupportedFilesInDir( QDir dir ) const { dir.setFilter( QDir::Files | QDir::NoDotAndDotDot ); QStringList filters = ContentFactory::getSupportedFilesFilter(); diff --git a/tide/core/thumbnail/FolderThumbnailGenerator.h b/tide/core/thumbnail/FolderThumbnailGenerator.h index 0230b473..04feb275 100644 --- a/tide/core/thumbnail/FolderThumbnailGenerator.h +++ b/tide/core/thumbnail/FolderThumbnailGenerator.h @@ -49,18 +49,16 @@ class FolderThumbnailGenerator : public ThumbnailGenerator public: FolderThumbnailGenerator( const QSize& size ); - QImage generate( const QString& filename ) const override; + QImage generate( const QString& filename ) const final; private: - QImage generatePlaceholderImage( const QDir& dir ) const; - void addMetadataToImage( QImage& img, const QString& url ) const; - QImage createFolderImage( const QDir& dir, bool generateThumbnails) const; - QVector calculatePlacement( int nX, int nY, float padding, - float totalWidth, - float totalHeight ) const; - void paintThumbnailsMosaic( QImage &img, - const QFileInfoList& fileList ) const; - QFileInfoList getSupportedFilesInDir( QDir dir ) const; + QImage _createFolderImage( const QDir& dir, bool generateThumbnails ) const; + QVector _calculatePlacement( int nX, int nY, float padding, + float totalWidth, + float totalHeight ) const; + void _paintThumbnailsMosaic( QImage& img, + const QFileInfoList& fileList ) const; + QFileInfoList _getSupportedFilesInDir( QDir dir ) const; }; #endif diff --git a/tide/core/thumbnail/ImageThumbnailGenerator.cpp b/tide/core/thumbnail/ImageThumbnailGenerator.cpp index e6d95416..05de416f 100644 --- a/tide/core/thumbnail/ImageThumbnailGenerator.cpp +++ b/tide/core/thumbnail/ImageThumbnailGenerator.cpp @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2016, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* All rights reserved. */ /* */ @@ -44,7 +44,7 @@ #include "log.h" -#define SIZEOF_MEGABYTE (1024*1024) +#define SIZEOF_MEGABYTE (1024*1024) #define MAX_IMAGE_FILE_SIZE (100*SIZEOF_MEGABYTE) ImageThumbnailGenerator::ImageThumbnailGenerator( const QSize& size ) @@ -54,22 +54,13 @@ ImageThumbnailGenerator::ImageThumbnailGenerator( const QSize& size ) QImage ImageThumbnailGenerator::generate( const QString& filename ) const { - QImage img; - QImageReader reader( filename ); if( reader.canRead( )) { - if (QFileInfo(filename).size() < MAX_IMAGE_FILE_SIZE) - { - img = reader.read(); - img = img.scaled(size_, aspectRatioMode_); - } - else - { - img = createLargeImagePlaceholder(); - } - addMetadataToImage( img, filename ); - return img; + if( QFileInfo( filename ).size() > MAX_IMAGE_FILE_SIZE ) + return _createLargeImagePlaceholder(); + + return reader.read().scaled( _size, _aspectRatioMode ); } put_flog( LOG_ERROR, "could not open image file: '%s'", @@ -77,7 +68,7 @@ QImage ImageThumbnailGenerator::generate( const QString& filename ) const return createErrorImage( "image" ); } -QImage ImageThumbnailGenerator::createLargeImagePlaceholder() const +QImage ImageThumbnailGenerator::_createLargeImagePlaceholder() const { QImage img = createGradientImage( Qt::darkBlue, Qt::white ); paintText( img, "LARGE\nIMAGE" ); diff --git a/tide/core/thumbnail/ImageThumbnailGenerator.h b/tide/core/thumbnail/ImageThumbnailGenerator.h index 922bbe64..745925cf 100644 --- a/tide/core/thumbnail/ImageThumbnailGenerator.h +++ b/tide/core/thumbnail/ImageThumbnailGenerator.h @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2016, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* All rights reserved. */ /* */ @@ -45,12 +45,12 @@ class ImageThumbnailGenerator : public ThumbnailGenerator { public: - ImageThumbnailGenerator(const QSize &size); + ImageThumbnailGenerator( const QSize& size ); - QImage generate(const QString& filename) const override; + QImage generate( const QString& filename ) const final; -protected: - QImage createLargeImagePlaceholder() const; +private: + QImage _createLargeImagePlaceholder() const; }; -#endif // IMAGETHUMBNAILGENERATOR_H +#endif diff --git a/tide/core/thumbnail/MovieThumbnailGenerator.cpp b/tide/core/thumbnail/MovieThumbnailGenerator.cpp index 2d1c2a1b..d7fc2584 100644 --- a/tide/core/thumbnail/MovieThumbnailGenerator.cpp +++ b/tide/core/thumbnail/MovieThumbnailGenerator.cpp @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2016, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* All rights reserved. */ /* */ @@ -59,10 +59,7 @@ QImage MovieThumbnailGenerator::generate( const QString& filename ) const const double target = PREVIEW_RELATIVE_POSITION * movie.getDuration(); PicturePtr picture = movie.getFrame( target ); if( picture ) - { - QImage image = picture->toQImage().scaled( size_, aspectRatioMode_ ); - addMetadataToImage( image, filename ); - return image; - } + return picture->toQImage().scaled( _size, _aspectRatioMode ); + return createErrorImage( "movie" ); } diff --git a/tide/core/thumbnail/MovieThumbnailGenerator.h b/tide/core/thumbnail/MovieThumbnailGenerator.h index 85e91e8b..f23ca352 100644 --- a/tide/core/thumbnail/MovieThumbnailGenerator.h +++ b/tide/core/thumbnail/MovieThumbnailGenerator.h @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2016, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* All rights reserved. */ /* */ @@ -45,9 +45,9 @@ class MovieThumbnailGenerator : public ThumbnailGenerator { public: - MovieThumbnailGenerator(const QSize &size); + MovieThumbnailGenerator( const QSize& size ); - QImage generate(const QString& filename) const override; + QImage generate( const QString& filename ) const final; }; -#endif // MOVIETHUMBNAILGENERATOR_H +#endif diff --git a/tide/core/thumbnail/PDFThumbnailGenerator.cpp b/tide/core/thumbnail/PDFThumbnailGenerator.cpp index ccb42a9f..e3f66a80 100644 --- a/tide/core/thumbnail/PDFThumbnailGenerator.cpp +++ b/tide/core/thumbnail/PDFThumbnailGenerator.cpp @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2016, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* All rights reserved. */ /* */ @@ -70,7 +70,7 @@ QImage PDFThumbnailGenerator::generate( const QString& filename ) const if( QFileInfo( filename ).size() > maxPdfPageSize * pdf.getPageCount( )) return _createLargePdfPlaceholder(); - QImage image = pdf.renderToImage( size_ ); + const QImage image = pdf.renderToImage( _size ); if( image.isNull( )) { @@ -79,7 +79,6 @@ QImage PDFThumbnailGenerator::generate( const QString& filename ) const return createErrorImage( "pdf" ); } - addMetadataToImage( image, filename ); return image; } diff --git a/tide/core/thumbnail/PDFThumbnailGenerator.h b/tide/core/thumbnail/PDFThumbnailGenerator.h index b46508e2..e1394e5f 100644 --- a/tide/core/thumbnail/PDFThumbnailGenerator.h +++ b/tide/core/thumbnail/PDFThumbnailGenerator.h @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2016, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* All rights reserved. */ /* */ @@ -47,10 +47,10 @@ class PDFThumbnailGenerator : public ThumbnailGenerator public: PDFThumbnailGenerator( const QSize& size ); - QImage generate( const QString& filename ) const override; + QImage generate( const QString& filename ) const final; private: QImage _createLargePdfPlaceholder() const; }; -#endif // PDFTHUMBNAILGENERATOR_H +#endif diff --git a/tide/core/thumbnail/PyramidThumbnailGenerator.cpp b/tide/core/thumbnail/PyramidThumbnailGenerator.cpp index f2352354..d4c03ff2 100644 --- a/tide/core/thumbnail/PyramidThumbnailGenerator.cpp +++ b/tide/core/thumbnail/PyramidThumbnailGenerator.cpp @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2016, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* All rights reserved. */ /* */ @@ -47,19 +47,13 @@ PyramidThumbnailGenerator::PyramidThumbnailGenerator( const QSize& size ) { } -QImage PyramidThumbnailGenerator::generate( const QString &filename ) const +QImage PyramidThumbnailGenerator::generate( const QString& filename ) const { - QImage image = DynamicTexture( filename ).getRootImage(); + const QImage image = DynamicTexture( filename ).getRootImage(); if( !image.isNull( )) - { - image = image.scaled( size_, aspectRatioMode_ ); - addMetadataToImage( image, filename ); - return image; - } - else - { - put_flog( LOG_ERROR, "could not open pyramid file: '%s'", - filename.toLatin1().constData( )); - return createErrorImage( "pyramid" ); - } + return image.scaled( _size, _aspectRatioMode ); + + put_flog( LOG_ERROR, "could not open pyramid file: '%s'", + filename.toLatin1().constData( )); + return createErrorImage( "pyramid" ); } diff --git a/tide/core/thumbnail/PyramidThumbnailGenerator.h b/tide/core/thumbnail/PyramidThumbnailGenerator.h index 172b1a1b..f91b4f36 100644 --- a/tide/core/thumbnail/PyramidThumbnailGenerator.h +++ b/tide/core/thumbnail/PyramidThumbnailGenerator.h @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2016, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* All rights reserved. */ /* */ @@ -50,4 +50,4 @@ class PyramidThumbnailGenerator : public ThumbnailGenerator QImage generate( const QString& filename ) const override; }; -#endif // PYRAMIDTHUMBNAILGENERATOR_H +#endif diff --git a/tide/core/thumbnail/StateThumbnailGenerator.cpp b/tide/core/thumbnail/StateThumbnailGenerator.cpp index 59c2a2bc..dd9bc76c 100644 --- a/tide/core/thumbnail/StateThumbnailGenerator.cpp +++ b/tide/core/thumbnail/StateThumbnailGenerator.cpp @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2016, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* All rights reserved. */ /* */ @@ -40,39 +40,39 @@ #include "StateThumbnailGenerator.h" #include "StatePreview.h" + #include -StateThumbnailGenerator::StateThumbnailGenerator(const QSize &size) - : ThumbnailGenerator(size) +StateThumbnailGenerator::StateThumbnailGenerator( const QSize& size ) + : ThumbnailGenerator( size ) { } -QImage StateThumbnailGenerator::generate(const QString &filename) const +QImage StateThumbnailGenerator::generate( const QString& filename ) const { QImage img = createGradientImage( Qt::darkCyan, Qt::cyan ); - paintText(img, "DCX"); + paintText( img, "DCX" ); - StatePreview filePreview(filename); - if (filePreview.loadFromFile()) + StatePreview filePreview( filename ); + if( filePreview.loadFromFile( )) { - QImage preview = filePreview.getImage(); - - QPainter painter(&img); - QRect rect = scaleRectAroundCenter(img.rect(), 0.8f); - painter.drawImage(rect, preview); + QPainter painter( &img ); + const QRect rect = _scaleRectAroundCenter( img.rect(), 0.8f ); + painter.drawImage( rect, filePreview.getImage( )); } - addMetadataToImage(img, filename); return img; } -QRect StateThumbnailGenerator::scaleRectAroundCenter(const QRect& rect, float scaleFactor) const +QRect +StateThumbnailGenerator::_scaleRectAroundCenter( const QRect& rect, + const float scaleFactor ) const { - const float topLeftFactor = 0.5f*(1.0f-scaleFactor); + const float topLeftFactor = 0.5f * ( 1.0f - scaleFactor ); - return QRect(topLeftFactor*rect.size().width(), - topLeftFactor*rect.size().height(), - scaleFactor*rect.size().width(), - scaleFactor*rect.size().height() + return QRect( topLeftFactor*rect.size().width(), + topLeftFactor*rect.size().height(), + scaleFactor*rect.size().width(), + scaleFactor*rect.size().height() ); } diff --git a/tide/core/thumbnail/StateThumbnailGenerator.h b/tide/core/thumbnail/StateThumbnailGenerator.h index d4866e87..4bca0bf0 100644 --- a/tide/core/thumbnail/StateThumbnailGenerator.h +++ b/tide/core/thumbnail/StateThumbnailGenerator.h @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2016, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* All rights reserved. */ /* */ @@ -45,12 +45,12 @@ class StateThumbnailGenerator : public ThumbnailGenerator { public: - StateThumbnailGenerator(const QSize &size); + StateThumbnailGenerator( const QSize& size ); - QImage generate(const QString& filename) const override; + QImage generate( const QString& filename ) const final; -protected: - QRect scaleRectAroundCenter(const QRect& rect, float scaleFactor) const; +private: + QRect _scaleRectAroundCenter( const QRect& rect, float scaleFactor ) const; }; -#endif // STATETHUMBNAILGENERATOR_H +#endif diff --git a/tide/core/thumbnail/ThumbnailGenerator.cpp b/tide/core/thumbnail/ThumbnailGenerator.cpp index a609eebc..3b177fc6 100644 --- a/tide/core/thumbnail/ThumbnailGenerator.cpp +++ b/tide/core/thumbnail/ThumbnailGenerator.cpp @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2016, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* All rights reserved. */ /* */ @@ -51,52 +51,50 @@ // TODO change this when the slide show is adapted to keep aspect ratio #define ASPECT_RATIO Qt::IgnoreAspectRatio -ThumbnailGenerator::ThumbnailGenerator(const QSize &size) - : size_(size) - , aspectRatioMode_(ASPECT_RATIO) +ThumbnailGenerator::ThumbnailGenerator( const QSize& size ) + : _size( size ) + , _aspectRatioMode( ASPECT_RATIO ) { } -void ThumbnailGenerator::addMetadataToImage(QImage &img, const QString &url) const +QImage ThumbnailGenerator::createErrorImage( const QString& message) const { - img.setText("source", url); -} - -QImage ThumbnailGenerator::createErrorImage(const QString &message) const -{ - QImage img = createGradientImage(Qt::red, Qt::darkRed); - paintText(img, message); + QImage img = createGradientImage( Qt::red, Qt::darkRed ); + paintText( img, message ); return img; } -QImage ThumbnailGenerator::createGradientImage( const QColor& bgcolor1, const QColor& bgcolor2 ) const +QImage ThumbnailGenerator::createGradientImage( const QColor& bgcolor1, + const QColor& bgcolor2 ) const { - QImage img( size_, QImage::Format_RGB32 ); + QImage img( _size, QImage::Format_RGB32 ); QPainter painter( &img ); - QPoint p1( GRADIENT_START_X * img.width(), GRADIENT_START_Y * img.height( )); - QPoint p2( GRADIENT_END_X * img.width(), GRADIENT_END_Y * img.height( )); + const QPoint p1( GRADIENT_START_X * img.width(), + GRADIENT_START_Y * img.height( )); + const QPoint p2( GRADIENT_END_X * img.width(), + GRADIENT_END_Y * img.height( )); QLinearGradient linearGrad( p1, p2 ); linearGrad.setColorAt( 0, bgcolor1 ); linearGrad.setColorAt( 1, bgcolor2 ); - painter.setBrush(linearGrad); - painter.fillRect( 0, 0, img.width(), img.height(), QBrush(linearGrad)); + painter.setBrush( linearGrad ); + painter.fillRect( 0, 0, img.width(), img.height(), QBrush( linearGrad )); painter.end(); return img; } -void ThumbnailGenerator::paintText(QImage& img, const QString& text) const +void ThumbnailGenerator::paintText( QImage& img, const QString& text ) const { QFont font; - font.setStyleHint(QFont::Times, QFont::PreferAntialias); - font.setPointSize(THUMBNAIL_FONT_SIZE); + font.setStyleHint( QFont::Times, QFont::PreferAntialias ); + font.setPointSize( THUMBNAIL_FONT_SIZE ); QPainter painter( &img ); - painter.setRenderHint(QPainter::Antialiasing); - painter.setBrush(Qt::black); - painter.setFont(font); + painter.setRenderHint( QPainter::Antialiasing ); + painter.setBrush( Qt::black ); + painter.setFont( font ); int flags = Qt::AlignVCenter | Qt::AlignHCenter | Qt::TextWrapAnywhere; - painter.drawText(img.rect(), flags, text); + painter.drawText( img.rect(), flags, text ); painter.end(); } diff --git a/tide/core/thumbnail/ThumbnailGenerator.h b/tide/core/thumbnail/ThumbnailGenerator.h index 24304362..d053fddf 100644 --- a/tide/core/thumbnail/ThumbnailGenerator.h +++ b/tide/core/thumbnail/ThumbnailGenerator.h @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2016, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* All rights reserved. */ /* */ @@ -40,27 +40,27 @@ #ifndef THUMBNAILGENERATOR_H #define THUMBNAILGENERATOR_H -#include +#include #include #include -#include +#include class ThumbnailGenerator { public: - ThumbnailGenerator(const QSize& size); + ThumbnailGenerator( const QSize& size ); virtual ~ThumbnailGenerator() {} - virtual QImage generate(const QString& filename) const = 0; + virtual QImage generate( const QString& filename ) const = 0; protected: - QSize size_; - Qt::AspectRatioMode aspectRatioMode_; + const QSize _size; + const Qt::AspectRatioMode _aspectRatioMode; - void addMetadataToImage(QImage& img, const QString &url) const; - QImage createErrorImage(const QString& message) const; - QImage createGradientImage(const QColor &bgcolor1, const QColor &bgcolor2) const; - void paintText(QImage &img, const QString &text) const; + QImage createErrorImage( const QString& message ) const; + QImage createGradientImage( const QColor& bgcolor1, + const QColor& bgcolor2 ) const; + void paintText( QImage& img, const QString& text ) const; }; -#endif // THUMBNAILGENERATOR_H +#endif diff --git a/tide/core/thumbnail/ThumbnailGeneratorFactory.cpp b/tide/core/thumbnail/ThumbnailGeneratorFactory.cpp index 8e3341b9..23619e78 100644 --- a/tide/core/thumbnail/ThumbnailGeneratorFactory.cpp +++ b/tide/core/thumbnail/ThumbnailGeneratorFactory.cpp @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2016, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* All rights reserved. */ /* */ @@ -41,8 +41,8 @@ #include "config.h" #if TIDE_ENABLE_PDF_SUPPORT +# include "PDFContent.h" # include "PDFThumbnailGenerator.h" -# include "../PDFContent.h" #endif #include "DefaultThumbnailGenerator.h" @@ -52,62 +52,49 @@ #include "PyramidThumbnailGenerator.h" #include "StateThumbnailGenerator.h" +#include "DynamicTextureContent.h" #include "MovieContent.h" #include "TextureContent.h" -#include "DynamicTextureContent.h" -#include #include -ThumbnailGeneratorFactory::ThumbnailGeneratorFactory() -{ -} - -ThumbnailGeneratorPtr ThumbnailGeneratorFactory::getGenerator(const QString &filename, const QSize &size) +ThumbnailGeneratorPtr +ThumbnailGeneratorFactory::getGenerator( const QString& filename, + const QSize& size ) { - const QString& extension = QFileInfo(filename).suffix().toLower(); + const QString& extension = QFileInfo( filename ).suffix().toLower(); - if (!filename.isEmpty() && QDir(filename).exists()) - { - return ThumbnailGeneratorPtr(new FolderThumbnailGenerator(size)); - } + if( !filename.isEmpty() && QDir( filename ).exists( )) + return ThumbnailGeneratorPtr( new FolderThumbnailGenerator( size )); if( extension == "dcx" ) - { - return ThumbnailGeneratorPtr(new StateThumbnailGenerator(size)); - } + return ThumbnailGeneratorPtr( new StateThumbnailGenerator( size )); if( MovieContent::getSupportedExtensions().contains( extension )) - { - return ThumbnailGeneratorPtr(new MovieThumbnailGenerator(size)); - } + return ThumbnailGeneratorPtr( new MovieThumbnailGenerator( size )); if( TextureContent::getSupportedExtensions().contains( extension )) - { - return ThumbnailGeneratorPtr(new ImageThumbnailGenerator(size)); - } + return ThumbnailGeneratorPtr( new ImageThumbnailGenerator( size )); if( DynamicTextureContent::getSupportedExtensions().contains( extension )) - { - return ThumbnailGeneratorPtr(new PyramidThumbnailGenerator(size)); - } + return ThumbnailGeneratorPtr( new PyramidThumbnailGenerator( size )); #if TIDE_ENABLE_PDF_SUPPORT if( PDFContent::getSupportedExtensions().contains( extension )) - { - return ThumbnailGeneratorPtr(new PDFThumbnailGenerator(size)); - } + return ThumbnailGeneratorPtr( new PDFThumbnailGenerator( size )); #endif - return ThumbnailGeneratorPtr(new DefaultThumbnailGenerator(size)); + return ThumbnailGeneratorPtr( new DefaultThumbnailGenerator( size )); } -ThumbnailGeneratorPtr ThumbnailGeneratorFactory::getDefaultGenerator(const QSize &size) +ThumbnailGeneratorPtr +ThumbnailGeneratorFactory::getDefaultGenerator( const QSize& size ) { - return ThumbnailGeneratorPtr(new DefaultThumbnailGenerator(size)); + return ThumbnailGeneratorPtr( new DefaultThumbnailGenerator( size )); } -FolderThumbnailGeneratorPtr ThumbnailGeneratorFactory::getFolderGenerator(const QSize &size) +FolderThumbnailGeneratorPtr +ThumbnailGeneratorFactory::getFolderGenerator( const QSize& size ) { - return FolderThumbnailGeneratorPtr(new FolderThumbnailGenerator(size)); + return FolderThumbnailGeneratorPtr( new FolderThumbnailGenerator( size )); } diff --git a/tide/core/thumbnail/ThumbnailGeneratorFactory.h b/tide/core/thumbnail/ThumbnailGeneratorFactory.h index 42d6ea57..d61d0c6d 100644 --- a/tide/core/thumbnail/ThumbnailGeneratorFactory.h +++ b/tide/core/thumbnail/ThumbnailGeneratorFactory.h @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2016, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* All rights reserved. */ /* */ @@ -40,26 +40,26 @@ #ifndef THUMBNAILGENERATORFACTORY_H #define THUMBNAILGENERATORFACTORY_H -#include +#include + #include -#include +#include class ThumbnailGenerator; class FolderThumbnailGenerator; -typedef boost::shared_ptr ThumbnailGeneratorPtr; -typedef boost::shared_ptr FolderThumbnailGeneratorPtr; +typedef std::unique_ptr ThumbnailGeneratorPtr; +typedef std::unique_ptr FolderThumbnailGeneratorPtr; class ThumbnailGeneratorFactory { public: - ThumbnailGeneratorFactory(); - - static ThumbnailGeneratorPtr getGenerator(const QString& filename, const QSize& size); + static ThumbnailGeneratorPtr getGenerator( const QString& filename, + const QSize& size ); - static ThumbnailGeneratorPtr getDefaultGenerator(const QSize& size); + static ThumbnailGeneratorPtr getDefaultGenerator( const QSize& size ); - static FolderThumbnailGeneratorPtr getFolderGenerator(const QSize& size); + static FolderThumbnailGeneratorPtr getFolderGenerator( const QSize& size ); }; -#endif // THUMBNAILGENERATORFACTORY_H +#endif diff --git a/tide/core/thumbnail/ThumbnailProvider.cpp b/tide/core/thumbnail/ThumbnailProvider.cpp index 84ccfab9..62918815 100644 --- a/tide/core/thumbnail/ThumbnailProvider.cpp +++ b/tide/core/thumbnail/ThumbnailProvider.cpp @@ -47,6 +47,8 @@ #include #include +#include + namespace { const int cacheMaxSize = 200; From 7b23e1ade5b23f4ef79939590932e3dbb1e1d8d1 Mon Sep 17 00:00:00 2001 From: Raphael Dumusc Date: Thu, 23 Jun 2016 12:01:02 +0200 Subject: [PATCH 4/4] Launcher file thumbnails use correct aspect ratio, Session preview images quality improved --- apps/Launcher/qml/FileBrowser.qml | 15 +-- doc/Changelog.md | 5 +- tests/cpp/core/StateSerializationTests.cpp | 13 +-- tests/resources/state_v0.dcxpreview | Bin 35115 -> 48897 bytes tide/core/StatePreview.cpp | 26 +++--- tide/core/StatePreview.h | 6 +- .../thumbnail/FolderThumbnailGenerator.cpp | 86 ++++++++++-------- tide/core/thumbnail/PDFThumbnailGenerator.cpp | 4 +- tide/core/thumbnail/ThumbnailGenerator.cpp | 5 +- 9 files changed, 84 insertions(+), 76 deletions(-) diff --git a/apps/Launcher/qml/FileBrowser.qml b/apps/Launcher/qml/FileBrowser.qml index f2dd282f..f088a5de 100644 --- a/apps/Launcher/qml/FileBrowser.qml +++ b/apps/Launcher/qml/FileBrowser.qml @@ -60,13 +60,14 @@ Rectangle { GradientStop { position: 0.0; color: Style.placeholderTopColor } GradientStop { position: 1.0; color: Style.placeholderBottomColor } } - Image { - id: thumbnail - anchors.fill: parent - cache: false - source: "image://thumbnail/" + filePath - fillMode: Image.PreserveAspectFit - } + visible: thumbnail.status !== Image.Ready + } + Image { + id: thumbnail + anchors.fill: placeholder + fillMode: Image.PreserveAspectFit + cache: false + source: "image://thumbnail/" + filePath } Text { diff --git a/doc/Changelog.md b/doc/Changelog.md index 6d83844e..75dd31e2 100644 --- a/doc/Changelog.md +++ b/doc/Changelog.md @@ -4,7 +4,10 @@ Changelog {#Changelog} # git master (1.1.0) * [46](https://github.com/BlueBrain/Tide/pull/46): - The Launcher creates and caches file thumbnails more efficiently. + Improved Launcher: + - The creation and caching of file thumbnails is more efficient. + - File thumbnails are displayed with their correct aspect ratio. + Session preview images are of better quality (no longer pixelated). * [38](https://github.com/BlueBrain/Tide/pull/38): Fix a segfault that occured when opening grayscale images. * [36](https://github.com/BlueBrain/Tide/pull/36): diff --git a/tests/cpp/core/StateSerializationTests.cpp b/tests/cpp/core/StateSerializationTests.cpp index 8009a1fe..4adf2f54 100644 --- a/tests/cpp/core/StateSerializationTests.cpp +++ b/tests/cpp/core/StateSerializationTests.cpp @@ -414,16 +414,17 @@ BOOST_AUTO_TEST_CASE( testStateSerializationToFile ) BOOST_CHECK_LT( previewError, 0.02f ); // 4) Test restoring - DisplayGroupPtr loadedDisplayGroup = boost::make_shared( wallSize ); - StateSerializationHelper loader( loadedDisplayGroup ); + DisplayGroupPtr loadedGroup = boost::make_shared( wallSize ); + StateSerializationHelper loader( loadedGroup ); BOOST_CHECK( loader.load( TEST_DIR + "/test.dcx" )); - BOOST_REQUIRE_EQUAL( loadedDisplayGroup->getContentWindows().size(), + BOOST_REQUIRE_EQUAL( loadedGroup->getContentWindows().size(), displayGroup->getContentWindows().size( )); - BOOST_REQUIRE_EQUAL( loadedDisplayGroup->getShowWindowTitles(), + BOOST_REQUIRE_EQUAL( loadedGroup->getShowWindowTitles(), displayGroup->getShowWindowTitles()); - BOOST_REQUIRE_EQUAL( loadedDisplayGroup->getCoordinates(), QRectF( QPointF( 0, 0 ), wallSize )); - checkWindow( loadedDisplayGroup->getContentWindows()[0] ); + BOOST_REQUIRE_EQUAL( loadedGroup->getCoordinates(), + QRectF( QPointF( 0, 0 ), wallSize )); + checkWindow( loadedGroup->getContentWindows()[0] ); // 4) Cleanup cleanupTestDir(); diff --git a/tests/resources/state_v0.dcxpreview b/tests/resources/state_v0.dcxpreview index 5f7cc2d0602d68ceb33c0bd5867a7a010c9163d5..51089f10c57628306ae01c8ec3ea9e0f7605bd51 100644 GIT binary patch literal 48897 zcmeFZWm6no8!kFXfCMKbxLXMB3?7_d!Cit4?(P;`g4^Iukl^kzxVyXi0E4shytVg_ zI8~>sT0VC5y>7W=b@&ejDfAD79{>OVx{S2AG5`So?-8(sg7ojIJ|D*U@AlqaTFVIl z!2J2&30ERqYykj}17yU%sk(zt+r8>+wDdL}9>$vI*Pp;%UvX*WYz4++@d0fqWq)e6Z8@h2;~M{fpZdAHN?;|Nrs-l`nAh z1{%zU!Kpq!Y+t+vk*Qx=Rh3#k!2BtX7ILuFB-GwhV2S2jAOnnuH!@y9{LWvnRp;+~ zDlS^*y(k+poovszE?$S~fu5bo6 z-5eBP%V)a{E(=|EKp(8np`8zU?;rTAZ8>a-rY~O0eD-W0J4)hpjEI5AbiD9Ng4>iQ z8_7Zk#5GrId}~!btT%U=`W7olxNU*)7seuL!@iuBT5&}%8ESan>()dV)N1{}XTVv{ zCc|4ev-R;2RPt4t5hf!(@Jk5_J6h)86^xPJefs(%YwF4gI}NS`sb8ONihsy))#1otRzDhA?{zQRKLNK`O&{463s`r z`7Xb9A1sy+wEUhUzhFQ+kyDmKSm}{@?GcPM@+vy%%t&2q`_gPbUZID|F>iE`BBX=H zc-I(b2f0~lpRdpM9f)Dr1m_(QMjX12Rc$RMLzOka3rAdPEaJ$v*U#eB2aFLf#cVHY zzkXC2boiy*VZv!LX)wmN{yA6c9};x|DDYZuwJdk-z7a}V6%mEFS;{#gkzW`;wo>w9 zt1jS8{)x^^lpfX;Xsj;mx8%uLv?F>7?vVt0RiHd;k4M6? zO5%zf`cd{S;J)9PFnPsQ9+}-F3nxU+?z^OuLYyXa{;}hU1 zO!B#w?3Q8`Vze9-B6esfrG2YV>uRsOi;$+XKE{6}FQ2w}WZg97T(lyf8J%p-;k}qY zm*Kuyx>w*J`8M|ZNqun*IM&?_2Usf;V*({q#!)4oAXJ|A#&LX5*)?8i^J6oGGr|=Q zaTczjvaeT3Gr)^;#CYI3(0x$EGWxJbTiA;Ff3A zey&*+%&3aI8BE2}yGQ0uEa|T1mDMJ%v&7ss(D+5h;0(kE84d^HP*-S0$xIMC9E( zyao^EWW5+q=sSf|a0}f0CFs?$)uawJb&RoX>r~KlG?SE4Qa%Dfy}O7-92LGHP-17l zc9_*JX`3;EHj5S(!^NHt-GLw)|5Fq>Hfcx7X|6Q=(49TDpIr8JoqZET%l+UC+m@*g zoq7|~uL{g%2tNXjMNsJBaU+8X9fOg8rVQ?FZoDL6Q(GDSs11KzqH}iNeUUh$FT082 zatCC_-GyGkUqg6?-vh6SPEwadKw_XskyBbCOR z)K%}^)EX8?U8DGoso+T(GhX?B&rBr$9D-C=|M}DKR_hK}=t&Qdk<_FVN5!l9Dr21- zASso1|0ThSGg-4zZ3f94#I$DVqDF0CdB#4!R&Q+;8!Kx{{Aax2Vw%lh2dfQ5Z`;35 zwc#?lmw!UQK<88+ydKbgrUUd^*_qnX2ehTA!cVb1jw4UIJGq-OIxXHR9*D0u^WY ze7K>N#Tdvh_JjxSnYps1zbirmgZ#9i{?TWrO~v%*Sd=Z=O9Z?c$Lkb_>D{pPl%2s9 zJ4uhd$4{X@UsmS_t)nb<@r}!@qr_{$U+I|6kK&_3DB`~(>CRXXpohv$Lp?U&Ekm%o zTKh2V;ljzcu?C*(LYRo08yi?;!6wDDM0rQ=Wy{=p&4(9AQcHJm=q#KXU9Ya)Z0tz} ztbHG_#mIB+2Z)u5F%C$gc@Z=5O&KhB6Q9V|i&La5ULIX$whafka15CZl6J_8Z_l(t zcdZ9_qjzO7x?azu=vd$tbW81r27;)JU`(C5%5O_b%cJ;)Z!SKNGK08Rv^17|YcIu> zx?o_#b1(FUMWNbzgMp;sDc~{`>D_P zia6ZkwwF5~%=->&R!uym+G7+2*W;cf8dpoO6QOzuau7 zgaxtoZM)wO6#kl5o>D>b`o{jX`D0gum26*f@1kRPrc|b!@@txiA@c94Ag6q6)?QZM z<)Ierni4EyzZ3H>`OEDt3OGs*p5rIUu4|pYcUSw_J}|HJIkFT_v0JX9Iep=-JeeK( zm`gvg#dkDu*Km&Yy@hT5Cp&3tiD|xgB0f)x819_{P+clzA@ycPIYprjDB-X@l~|cA zL`azca*LKq7}tZ}*-&aRh$gd>yS7-}|gH?>}tUt>5A|$T`qT**x%;07jFt;$xWKO>G zTC@ku|BfnTWgmB{@Qv~=y4^p;FXt!iP}0RUGD=E$r)kU%MpwZ7q(Mo83e}Zi$Pg2M zsO*73(#bVW&km>JnBRc9tg(vr4^^9cJCDv&L3@HGZ;fM> z94Y%M7y2CHZ(1ce+8)YQ9zKls*KCx=P3(4#jSiZNuW7&UURUv+!3i;$mF3L@7tiW# z(h~dv`z)?%G~13x`N}fiEk03*_n~IQYQ{9FZOzUPv?mbnwO$8~+`3)urQ7ncrUAZw z32QBzV+A1whrt?Vxud1PR3Xp0D&I{jhlX-*57rvd6%a3?r!Ek^`F`h;{Rr5bVk^FL z?T#f#o-4~&+BtDQz(F>4K2_s>^JGvUEJLvGVJn)RL8Y%tuQ^$;Oc?rN(n&70UMVh! z!3n57g&rRIXEJT&SpCMgk7iP~;SgKJhl>t3$66pS1LD~Zl=0F>p@OtTphi}xPJrJ< zj5i2y4x&M|gOf58&aEbdGz65W`;cF=6>+@-+P2(-R&B@t^nH`2x`}!h?$0}%?BgSQ zOmP)8M_=gK2y00K1~P`$m(!>2O;Ts4FcCtfr1mu1@8duHNRxy^vd)xI8`iFlK?&WgJ%_Y1{+iXHa5oJq%+@4N9)^Sk~P!F-YhO=5-qNZn<&T zwr;wS<4SN81A=b^hE$>5L%Z_wrg5W?zvyaX4ap|*+i3Sa?=Sn~oZ@4|rax9pHl!gg zE^=9^d?%CCN7{4*j>f_&ZqbiNO`V!`+>oK z7xX8E@t)AK2F~1M3@m#_M2@B!-CENWDmf*B8?J#kb27oE$hHuAj0duGdU2#)`ambEGob zXeQnH^?<1EXGeR^2~tZg$f~2ibj@a^GV=74smbwy{f}*Um@GJEcT)m{w9)Ly=Ge|p zB-EX>^O3Cw9Dh80Y(MnZgVF5_%(kDYqFc!ZqAFkwCY7-`gyLZ~oz3g~AUO=}GHT$m zrAn`4mPs`q<>rOb#s?Y3OkX*^>*^l~U46ZWY_)G@=F5PQ9n5sk?B_GnM+4HXKMstB zthqfkZt8L0C&z2d*YX|(h;rie{9Y#dY2}6I-;n8G3BoLnqY$U8=EeS+=sNg3T12GXp3H{I|xZLT|I2zy*ny^|+^wC(4x) z3ZEa$v2%==tQClJXKj;YH89?9ePE{`+q)l9E>2el@2$`t&EvEbis4RDcO=9k%A}bo z(~Z;5TIZluxXqjWl341Z#vru1C>&L~g9Nj_ubsz3?mr&wI92?}F!kxRhtoK|gULlG z8P~n#ZeAcw_PqrWOR)K{CnSY$d-7wT#LP-0!OLIxfR2+U_lHzwAbqi$Vs)zuAN8RFrX#))o4X6w=?fWGVmZtqEfF z8pix^9oW}sI=jmtcnrY$$-U8Y5EVZ&3zrkdw*q2I#4e7IWVk}}fh18m0X+9t?PsFH zL{{oJ>2G6}xerri;>Wz;t-pSY8PJ=zF44=Tz&0is9ORnBpQ&DQ1KKSJubGIG#HG5k zf3M1~wJ^<>JCTL#aksJ!9I(1I_u*eDG&x^U>M0w7vwHbb_K%t4BND=o0jlMN2>BSh z{kGJUd)jrMcQSt&u^UCHE2`HMmqf5euBT zig@Y>LWgvv*|vJZ47yMwi^B1}%2WPl7fS^g{D=@v{v>7&<>@InPkv)h>Cu;!z39VQ zjWOr~7hq#d6R@@>m@au3I(U?kWq9F{dqJgBo9xl5KfXY=xq&%7fClY}?;ef{P&Qd}&_kuqe0@*bSeujCe@$~P4{_h+n zC+en6C&x8hheF#3z(>y=Y{?@ic*hbqOsFPW27{+sQixi_Q<=pPEsNG3CsoFP`_A=w zc6MEL$K=XUy;r_~N8G+N=C}gD&j+yBvO?x>SUY4B@Rv!8UEFXaNG+ZB!F+~Z)-bfn+tYgC|-kz%*Gj}@v{LiFk=TL&$S;> z*izk_t?fQqvqd`VE}NO&vYg_T_$6`21fXscuH$w9!FpPcUaPN*k?L zqEeg7>&|uo7^&)5ThJzxMK#;jL)%y}#0o43slq*ELqYkgb)?;egDurIkuzISlSMMr zlC<<=#ND*aV*6i+UF_>lo6m|!zy<6gLM{gp0nAzf(<>xlWuu>q@kPbSn$fyQ+;r^@ zBAALOLX6tD%-Mg$;WL(j$F+aV?tk4ickZcaEWviN?V06GMNv7)qzRQ3Tv3IJj~+_K zP32<^3x;X7>ds>iE)jmKo*%lpZITp8oc_*}F*e^9U6d#Eu-tko(8HBK$3<_B(@DXP zLMg2-Cr91Nn;Mi-RqJEtiZ$kM8T@mw1w9c>3{7;FGl)Fy?Yfue#ZUZ-qWG3xdGLX_ z_{fc3D}M?<)+Wfpk0Nj&(d9=-ZgygP)R3Kbnw8YfT_cYpi(~8FEWyetypmeWT>Q6s zT`?-$Whc@Er*m)l7mcX@hB%00eO)0v!22l{UK84zz460+hmP83!fL0#(Vl6AcrHKUkHC|u0Jo--sBpiRJsjF65og_K6{1j> zq89e`*^))aw+nv4Bt)0eA9R{cHcfu=HIxv4j_M%73a)&=!!^vDE{8UK^F8SWv2Aqv zR%Sq)#7DTOD!<4Yo}Md)>N5`5cyhKPH~HlYk`Cguct5@oU-D?%-;<9X-sM?n}3wPL4H><({pd*=s$#-3p_H^GOeIJ&4hAu4Ya7{Dip zH_k7U0Spd$sucF{YVrh@;UJWh6M5ir()MT!hByi+I1#cA2-8lmdGFTOMfati_WGFQDBpSGG)UST_e$4}#pR!5ikd`6rg(IED0AVzG8D=~Hp zR@jR_Vs4~tB{g!_!)GbE2{40_E17zqP$0(85MdM$^QK=@swW3)hj)kaj(+C13zhOx z7m}&YnStO;+;Cc(`L>1!ikf4YE+yLjk^jeVt8C))(?Odd7k~il-Ne@zy<`MZuFnOl z8NK;bc^G}VxvEgBn6Ab}ecZrTHVDo;&KHM)yijyl0Osx)b=h9QlW z9-AZVTNok47z-Qz3^SWl#yEP{6=3E%C!q)db0z)3*Q(+LAK=vfk!S_^nQ5Fh>R+LG z_q1~ml|I%Awa>kkW`oztyGegO7s*ro0iMds>Mr!F8YBzPydTslpF^7N%tS_~t}z_v z#wT#VhgU)n``%7Q;zE2%R?{im8!i#n%)`=X94!zc-Kbr75rd{Tp=4(oBt_a{zQCkU zDftI4^fx#_-23#2LgFOuCq9Z;&WSaOEDsu*nBgH(2-cC<1pDn@w>1&8xQ+_~BpS54 z$1NpL2zTlgamzICpol+y0&|clwWC#*QJ!=&Gv-cL`sm#Tb+Rd?33H0hl35hDO8?Jk z+qA|;A5;3h(vnyQgwgjo0j~I5ziYc|FYLqi-@6!ViHqa61e~2!T%)8)o6v5**Dp>u zyS~f{C;aJY7~FSH_nD1GULiUxN_o=OnfTO>f^4GCybLFymnttop{u|S8<(1pjYH~K z=A`?}*Pcma!j0sUfaPX%F_VVO8{$Ve`Ly67J%bvTYaT~$XYqwl$FqTEG}oA!IzJnP za{qrkh`TgpK9^Q$xs5~Ksg2zfXG}v{6#3Zg5j8Wro}n@O<$7%T8_hA3i$Ubz^~uu{ zGGj_@U96G;DdRDlU_f|pT(qd1Qa#21wFa+(%6N~ZA=k}~p5mc8alrza*C~6fkYiS; zkWUB}QgUwug~YI)@FWaDZ(#KQ?ko6UGy zl+kx;<`8V+Qz5zUjNvhcN{ulKnW<7*t>OZVDLK4#eW_;e3liHEC#*hm#9yU;FQqE| zV79@vDc_HCa(B7@F@w`%!e&aETs$|E1tnK11Po-C=o?70oGLWt4~g}@B*oneIU$3P zD7I&YTdAeK5F)Hun#R}=40D;Gajy`ZrIjdj$w>WIe4>`nE5~e{X;$%V`gO6EE90(I>uL=*oFMnGQctThqRtkdd-?A**Cyx12txE?i_));-TP}W zgLA2Zv-ZkBNqL8h$Sps~G2$qYwz0y7Sdr_On^{!O2Kto|NuPAZC8C(J^9}4OeizhM zCqJ^)DASD5gjqdJbN-Mf9^e{`uPp5#GVbF-&q#|S{`O~g>8jwOrqYqay_{)sDJ(r` zmv%){N`x3G&(0#XE>eErVp#~{dx;Zn_N4Qj1{n# zydon07;vYEZb4lUbCzD6h;x1AlKkmMXjl^UF8M(fWYk}h2mr1M!(uWpbITi3h4gP_An{lMUG~e{ zd34A>bfjq^F-Q(#0FJa`X#d`9_GTk*Hj*`Glmy^;FD+d46|Y*RMMWz_;Zs6#=_a;W zHJcS&c5AJL6hF}s{nwUL#|SxNjEypyL|3EcYK)f}MnN3ZW;=%;Jigqtmm=+>`8%~i zNiKF@75$n96EG}(KH1%p3O^qyS=fBNGrskDnrDj!7UdBkT9DKpPO1+UG*Q6(ieB+rAHFh`U!MHgm2^6u6r3wUg!Pj$#&%;SbGbvgTM|-)JY5IK*Jadfd4J zOJEbKQVhaxte|;B$Cb1LKe46b&k+7(CzFWrtc`hzs`BhN*jej*G85&kTbOS1u&Qvb z<2xv1@j-|A?UMq8u9h%0_o*chp}tU$0}27!VQM~_iao2JX;hzhYoR89jw{oRK9-JK zkS6+5*!?wQ1gvDm%(s`reNOfbz7=F!!0(OdZ}93S{NW==i8dw;eZ7`j)gi+037Qw? zZbfm+T@JdKl?M=G%641>4IqsjTlLR7WKV2&FtV;ftHV&~9TGHb0>b@T!H$~|eL&aw zxR%kv$Hx)x>sLklttkjV^OSMYcQahkQ-I=Y3|m41^0TuKWNIq@=OHSD+KD0c@`LES z#1}tbeQTaF2xk7Y?a}23PdD|N_`^p_H|k}121_jPi&d=Lj1^L0quEm5O*N$$9qmKu1St?NJEA+rkN}2;>W^FeF69sw| z_iGz(bA43RP{;A(^RdnQm<3;ijk`v__EoYABKV;9;xT5)3t%x>?g+a z=RmsY5=WTe1@fli`jZZL#Sh@Z)N4(Ya{Mw6+*w>%scD$zT*8t&=>kHq;C)aKe|fY@ zH_FaH7j%+ENV1y_W&o>KzZ4Ct1&g;$^7#OC#5`ai!oM2oFis7pdXyZ$-&71MLToSD z40d}RUx7n$*sR4Akla`a+=%$xyRR3iViz+|UO4NeQ-~P><1j;2Jp2h_kl?lqL66=K z4zpjSYll(TbBZTtI>0@46f@M+ib{Wk6-6D9YlnPF@-(;TzxK~89(sroc$X{hVk#`d z83ZMbF4DuFOMJZUf?Fyvwlfn9)Vw*y+Ch;s)qbZcxNU~Tq{f_{r-^8yxsk0clfR27 zE+uw!FuGrig>6==x9l33AH=W17l=;6bMW&b-W4NAL& zlZ`Tgol*m|t_MXyNwk4G5!1HdbH`&G`k8gbB9|FZTXrcEJ$NBD3Y$u6- zh8^FCHSO~PtUbH2bI*sEL~wWyin&CS7%;={b%P@1`;A{|(|Nk4o`Xf9XHimS+2zop@;Lw(2_w5$u^n=?(5O#L7}~0v~kPKUC9+|MA-Icpfb{ z=Y&11{La4?ibt#CVFF-3Qhr=X4Zw>`hXhFF=bj{VkB>(}D8{w#95amQT?(XqDm1*J zBgv&lR~uapL}s3ps0pYid2wyK)XE$x*^Fq+PWsI7icj`_ETpQxUbD`XsqAQ@$<%gV zJ&`p>+WB7bz}v%$U&D@0iD(a$?tl*EMSGc%$e7nYeg||9TV&6^uk$c(jUn+cl%M$b zfBg1bR-d|Kw`%aQM~rrh#p{n?iBGI){rqOUoDzq_W1tGtbA31F`YSG8y7KtTF~9pp zzu1M2eLL*dk-Ac}os4RATPP~0#0|Q9!W*-k9-F0DA`)R_rJ{k`$CZ^8-9|4e#rCsO z;(>Q8ez!bu_V|qtSALIc<#!syS;8VjdvPzw0C(7mZ?;pcUKbZOo@XA)%EH?3aY&3A z0Gz>LAOJp}qo{Sw@HmOMnlM@NZdZqtwoy$s7&ivjXKH^QDb2IBj?9dI&!9m2KSG!@ zdd@vT>FyU3TKj@3Dhb|ReFNJkBic5L0*9Wvyj&Z?Hdruaag{Tly`|O4T~fpQS`j?u zH3LI7XkpbVf8-;Vq&K^+t@Nn3h5etb0UeoKGWb8ZnGHwxAwR#M@|hTcwS$Rmj;sP$aB)=9V+&zas!|N%NB+D#-r4Kl2crU4jMJR-<`6hw3$d;T&<9vPN4{ z7m;`l5df5(H=^rdCL&I1U5~A2USPYNv_htea%|cp=ZjxOX)|@`KeKp0O#4H>=ndsX zDL_iDeoxr^BX1pH2kX5M;rl}G-annu8=g;ZdRZCmXSM%`_ge2m&T+S#5#L%$I`Rm z?tnNuE>;#ly6^a@Xcg(=FEgOp?Y_MKN~!)TFGGq;FV`8thW7@se;5?F%$wtq)t;#` z+Foqqokp_hKulb*xV9qEmq4_G6kRTAo5sPx_4TYdu9-Pz0JYaJ@=$%F_7onuebNQu z?4!6+2q%U^fRv&1I~uhM3n}ta$y<9>jJu~y6OxKBH!GBEp;Brm(9WC&{k`i`VNJfX zjb6%OOMok zqlb=+o=j7Z^|xGD(FsO$?3Z;k`Qy)jVcXhBhR2(`epM|D&)Ze60)B7EzTmfbV*i|B zX!fTUPwp+DP$3IOvyWu`_lvypAB z@3rm-+Tfx$v~m3reM4dYS75;9ssCY|4?`(fVLyz}fNEfHe!lIw^(upae=j$bbnn&a zAdK&lrd3g90TMtaH!Cfd#EQACj18XW?n;RHPXLeVl`pDV-d^W6{_~LvlHUIPHCOA~c+WkQ z{VFh*oCd$Yia9Kd!j|+3nR^G`_`ciYAEE|~mlollp>c1jrI2FroBDI#4(l9i!jmB{ zJ_J(J?$vX`54`sr{^=IycempgTIJDi1$TdI@L;MBji}mrdhN%A?(P&rw^{ty02faQ z8}&|F8FV5`8_RAbEKH#h=-N2h5S(87aiKT)s)w)4r^0=ZixpMMVa5^PuAHb!ozzcrWaQ;Q-j=9RLw}VOziNZd|IZ7U=Ql4~Go# zG9D)xyyf{@)>0fdcE~Fi>kNKR_3FA!nIFJS=rd zpQ#uG?KVTpp>8K``xuh~aqeYpSfqQ)OQMy3R?*(De>r#Qqn=m}6MK&)HnBB@jSOMn zEHVcceB(o58-fK|Kp1d$3?4TEau~c-IqSh=cnco`i^aD}W{sniYfmd$_4RI$z~Y=$EEX$oxf6#FP;dr(?|B zIBsw0IuN@^V!h(02KuBkV%R>ot$+J#5s=X%3alB=ghN31hj0D>?w{8%?awa-C=f}# z55Ju^K`j!T;vKWq3QRPM#{C(z?;bv3-WPPyp;Z?Pvl`!#ZCrm|zp8xeqdH)5xVsti ze);pt4v6J!kmK zsU@kdFnQ%js)tIfc2VMJ+2aX=(^L7ogz5Fdamy+lBK)w%cS5xp$ad82LF3Dhs*q%- z3-u!0(3-P@BK1_FPq>r@c4TZ#lPc~XKqKeBW3cNGpY_t?@ zRO7}rQS93Ah~fI%1*T6zo62W`44;;*9|Ugtj~jqCBrcghj&Q=!rH?M3^>$7Sk6wu3 z_zwnE&Z&o1v{R2pyT3pV2V)|Ay7$3P&IZn$*D&vEv9?nWmOa?|n^$*Ynb?I@b~=<~+wg8qa`_9d=u%M#M@^Kn&YI5L^f?-AsbX7_V8 z&$D4D(5lU)Gi-A%5iK*SBH%&0A{klWM79IYA2Kf32Yb21yyCa>;K=sfw0*X2GvFTZ zoE^Pf-^s)#3vvgG=ea)$O_CUZO_buzKd$#RJ8FdUDlmQC(fg?Nw4%$LLR=YK@c?E; zT&85E(QUiOU-#EU%NjhZZ@`cT-o{7y>Fb>q!-Tu)ycmkELF^)mGAHL@3n z$4tN}aD#ct^SxmLB{^kz3ys_A6Ypiw6K;!tZ>d zoWI-K6&W@9hiXww<_kY}!<3f5Ic&Vf(Ght=a+YaK)0 zPQJWj++O5w=UI!g#ZR4Bo{bb!v)r^H{ml3tJoG$iB1wHvze2C@r{1K=L@q6RPVpM$%Bams~II6)*Pd zH=aFxAESk3R(e3B9TToIwp(F+yyR@<1fHK{&XN-01lifbAQ0J(;|G?5W}da-9Xk(! z;!2Kqy;R`q{khv!xZ>K#)vr&AuhVQTw&~nHp+EtNCMBlqnoINv_eTcz3$k_###?dx z$H9fpZGMl<*VyYNNV)!7e3j>CVc4IyWFg{=nhk9u8V(V}gRV$OF}K=)Wvj)hNE^*tjL{ICezpQ1&;QcYW_0SO0>}0zj4d7pE;%&s}M?USJ`o^!6DZ`w?_d zMG{sjli9CSZ3jms68{gqk`Z1n3l3YKXi<}cIJ{Plpr8A1eUMxFIUD{uRB$s6@M{#< ztLx7yzCaVsYHWO~DO1lo2f5p8hJVe}|I)&B@ke z((3zJipW~Ia$#{n<)2OJuo}@SM^cxKrCqc*D10WAE$kSSXXh(+0G= zbtC26<@jI}LKiOl_bw{&&p)U2o`V-{wAVuGM(<1(G^y=e=at|0A;m8of z_wRk2WcanMo`@uD{C!gve0q7VwpqL}7FwmB?pNI3E;`=%$F9S$g>Hsgk3wTu{H_-q zuZF3fwZ0h8sFU)ot@eD(w&%a_iDfS!onKqiaeq|F8YzTgI=#JQ?k`3?3`N6_d*%d?;Y0>bd9!uvI{;qJ+BNm zLKhSpUc85MZJ2OeTRK@<1CB)VWYPPHp_t46lOz5m+qPwow&z&5B9qIVryP?Gt&LUO z`gs-s#s=f>zuN(jJD~EaCS+*!eD`fT3un>HU zcIUB&`Y{(mGjS_} zsT>%w_H80PHEKR>gJ?^rNo7=^l4|!y<-Z1_=@Xzd1~=A1*J-iPTDw<^j;sEvt%Z$S zt6Jt=E35l-6%DTKd1~yf8wC{Q+2ElCGB7?sytMVmfSMj~tc#%3^@r!ypXm_K@ zqovyWwnbC*Ec<-g`8MR(S@~Hx{@MuzVZv)`0Xh}ij`wNL!{GS?Ka1dQKQ zzz)!0_~LE63hr{V|LJNRTePmaRViHS9QakA=`njJtsZ@>hj{Ou6A}-kKLG!ct4M0- z0~|B3!w?)fQw$p%FR^4aO)K$-TH9P;8|9FA_6Qsil?Sibwue6$MOLV^j=r>6(|skb ziYeh;`X9AZ1fL_JZDCPopM4}sQ1}Dk2g%9vHi`I_;Zim4xn_%qbjz!hkKt0|>1kJa z?7hh%GYO2lT#5#LBG&{U&iEl>NE1?0SLi&sSy*i?x{YVj;3th>$u3_8*3dP0Hoey8 z%=n&uY#Gx<{k2hKNjlC06X-szdYP4;B)9Ff4H0lEJ!u{4A5%I{P2n-p9mbEs{l)3R z3|Tnxrvn+s73uM&sGWj)`F8}|r(v|=t5a|Qqlutc0hF$aMuA@}Uh}9+ozPNgFOmtb zSB+Xf6YB?w700b%xRD@+n>8V^PNNRfJfX-l6*Qj-%jP-@mu2V@vUU2}m1DN+{AF6G z@F4QK6Wzx3SP|cS?c2fI_}+OS~U3a71rf5dH}7*Ksz9I>U>9<{IccVOE+Qj8uL68KFRFL%PU|ub!uia_7eA7^$lG_)x837-MA}=%hIib&rrxD!ZpPS8?7a?`c_i;8w@Y zBye_?7&n;HPF$$^b>~|u6pa-{>@A@LZKo4ZqO*PJmRLSoeP79JrS{)Wh@3pumf}vl z9UxnJI@MVs`==b4sUka~9sp!5o_7#K*DD7T`cD1CG$ah*E=$G%7{L4mmU;XDBG0TC>Y?;vA!!JvS0rSxa zo_%BHtE23M@{v}A+H(IIwWcd~cvU7B`1?}2u=|A0Jt~VgTjR!^3908UoBr#z26Rht z-3BHOuY-37Y;#QWb&)&dGXvJFtrY6G5}zCN)a#5QV#G2TL*Kaxg-Ve&cO74{+r0&C zY+30)##gtr#S9y7e8Qj zURI@@d77OG*s<5#B_+O3i*i+npEZ4>zhyrA9LP}}T0cKsNkVO2LOHnJ} zCs!g&KnCfvY^l`PRx61{ltYCOW?G?;3x1KxZtXX+iOvE|s{H#Yli^KG3^Il}<W(d1itQDw+G$;34$1+G6pmcF`+yhrVM}*dnR}_|PoU7nu#w!upsr-75d>K{P$c=`3%lqWJwONH~L!G3ses zMeqEMKTEnmW*PJauk;}$;@ zzDCtXHG(QHwR=9b-_p^Uk((8Sb`6<5+22M_G#@Xtg{LE@$}phW{NAbeYOM~^p^UaT zei|KK*aZ|AJB=513i0p}rEZ~Yzvshxtd{&kkHD4$8H3TMaA+^E+6h1l_%Ax1UBEUZ z@;hn33GeyMi5ED4)G}5!jBwvwK{n?hj6mb9Irbk_oMDU4tL^%{ulE*b=iQ9Gf$_S_ zY=lBvR4_$(RA79e9NryHmBZWI$MQTd0e3lCERewByPTl4>ibcHSr5{T3PZT80|{m* z3f-__V6p(Frgtr_DVV2gdaVp@@H`%ODi1QV?@Q2tFg4a{=E%vI4Cc^ z2xwWS>gih|jo?oC&tifSheb&^?R1DceHxDcnD|ZF6L;z7Ie)`*oIZo$QMkjg@ zvJ&BegN!NE?p5&(VXD5wGe;Jq>8wQO9kYRuxL$7#)0d_jVo%|*?`mMxe=eH7-k(mB zDmLzvs>Vnj@o49VL8Vn1MW;t?y>9hNb^DSJzu%8Eg{Gi0Hef@Yj z`S-w?=R$JH+zgh=?%|5WkP+fAp3Uz?oW32BQL`+M9bmhS%Y&I4Ts1NsT1Bq~gi#`f zjguG=#R*~w`gW9gNg5I$pp%ov^L(e*3E!2LS*yD$oXv+9zvY%Njii2Ii$k%cdd%p) zxeB_Uae`@iNEPy;`|Zu!Z5=7LBbAO1C7n^o9lzV{o^ zn}(;}mT9_CqjOx5}Fa=aBMK#UOnmubF{vdCzNx6GG4@E|rrdsnGM{F5F^=D4OlUyhD` z@Xs%%RXK4&NFj&TdHcbCJ)E2JEI_;m_&p*zk_3&2ZV_Js^hx5R@kZ%8-=MLMxLzTX zHSM*VLvE|%@;tgJ%sGFR$p7#L{Fl$6gO5K_qHgK!fD&mVhk9G4u7>Bw@P;Y z*5(R`Q3Mpu0l#@)V9zQwS6xyDlq)03sxQ#gy^Lfm@<=1r zLN2DdPpFB8og6UdKs#azvZIzKmEs7Q@VM5npJ=~0nBI~I;aw~bq1Om&0y)Dw7cnAj!ic({G;Ze2(3f>sHSiNP{=FeiNQ zZ{Z%1@DU z8{8TO`TX}h!cVTp%ixtzaITKS@`^Nm#zquwBNy_Y12K?KTPGF;^>w?sP-7~~@gIFu z{*1=xV~xl)G1h{)7+1Ah$y0Ywa%^KB=ZD!T{4xIRJlk21_OiCK!A|4Y&^J^Gc07n= z*o%uui2RRH2?O0Q615kaFT; zI2uP{+V)jy*H$!gqd?y6qkmq=X6X~@smud%4DV;9$h@{X=PBh$?t74l97J@KJt)(v z;i0X_q?*`+0J(zgQ#aP7EwyyTQI+C!8-)o;K>4WIj%zpm^T7B#=QO@32QUWzQV4_} z7`-`$oEJ{DDUe=^Zhd@S1%h`D!e8WsIk} zJgUZBv$wlA5yo`fcxAWJa=Q zZJQI@wr$=yXMN}XhVJ!tSM^iXNmdg{g%E^jpepWAdKS_^1a^2gJ~_n)=_$2$dy8!7 z;(BtM3*gELg=@7$nVut!AlA%De4yQ+#FBQ48IMKI+WT4|Ne&}wwE%W#HTL=gR#t3< z(yfz&j>UD5Q&#eOO5DETTJexO5lzf(*h^D*|E*PDUr}#09*Ni4s**rNe-5evqkM3#PqP9<9Pym0_F&b&uPx8mrk|Wdp4XZqT9tz zYDw4rHArpiy)0eVj;+H{^>syuL_+>-0n+bK<7V0(ty?0JcE@(qfIFg zhK&qrnk>!SgS^tI7*-!}ixO7WNo>C1utznBOp^owkB25GUN~YFBjj##VcU0{JbkeM zxj+0ubF+^}XF6umLCEANtrhZ8JfXne#YIvLs?Xj#jv@4u!$td#H_y0@#Q!BemWZ{0 zXAUIRykEpa-sSye^IRnFoFdKad`oH+VA^A`Sm^z+5Q@Mt0+uQtJ_akI`WDCV&wU~J z!&b#~?odkX)L3JWkhmF4bWmWVkHlwi+k3S_4aIxTo5rEqJ0doA?goWG!L_qSIk_(f@SiYM0Nb zjH%5rm1`%mugCR!4ZEqesW@q1uU81`Ly0ba1F~5Ou7_ld0cskSX{j{1aO#-xc=8-Dk( zhj*%K_knEp<>NL&uVhoUS3*~ z*rdB27W6lemLxC)ebQ5>T|l^KVkmTyH6LO2G1PJfK;&}j6gW@- zmgx!)cM=^v+a_}z$xzSDTl`-v2t87vPG708U_k>86$%hE@6k~}6fR+IBX1R-Z3Lp; zN$Q7z7ch*soWs;4`=`lNn=6F-m*1v)SK#1Q$8ol!$yJ)|>kj~R>Du6Ii>ErD1^+|G zomIdQubWs-aWYZ_7-px_7+ua4dmxB{RYa zq5#5%dKo|4B^=>uUtzbUK(kVEcI8fX=o!ulZ|`#TiI-QDG+O&eB3o$_5=`vNA(Qfh zH=TS3BPgMP>JQ$fwV*l%qF`}JVI}hy8VFMCDIz$XMo|dZJO~V->l^PsoF0JIr%v25 zVHR2V3)51@K{aFFsqW1yJWIn-`WSHoqawkBfT*=P?{v{Wn-^|7!tL4K4-q+xUTSq` z`4w&VELTEns3?N1#=E+(N^yd&6ovy`Us*c58n9D*&l+2H`!bbUnfsS)TN8101vXxi zr!TkpalvZeG;s=$=PqNS5`he6`f=IyYpq9_#6@LHY@SLxpfswtlFLQ0v|kCty~IV> zVhSw75cD`v!0%(r&O_Ne3c$UI)UOi^$tYH-6_`(&$k-azOiQ0(6zn@4&o6tf@;#~ z_>vGooXPNx(8iHKU%a5LqFQnC*6_vYue&s;~eqKc= zkhgmY0pEGkiKDRhpZQw65>j~quA2`afM6to{e0@*J5bvn@ZY9801$sWt=N;wtcG8h zkJtPf<}(QJpdaMbpQMLBMj@jBmRS-pj~UJJ)nmxP?v)6k<0NML8qoITDrN{0@iPlb zcISgXe}^Ls9rbb;{TVcOtN^1Y2VdC3v9DwZBbOkyK*u}~;lO04Cd20D=>41bFF4D) zT=fe621PF5i{>Q_2}m&9K+eCyaBWBTNY5@Q%!q5d6$=G^3UZKFwD5X zksk13#0o5-YA**vM_ zkA3JirFx7d+af2}`1D8wdvR!3-Xzx}ea;0#1o2e5Z}aI(<4jc4%ohd0O`AM?E+ z0(4)7RbL-Qcqim93oEcf7vQOkE!kN?`cGeais@AXJ{;mnw=f4l9tz{IYtf7qmJGO8 z6rlx9(7~%F-rrSJD@m=xR&M)b+K1C+$c7og_=pem)JC0SyV+04Z#CRHM#JOEfyLGGu>X}l>B6V3V) z-i%1cB(*N_7e`b#?GI#d4pl`LE}79X&SWq=0*K|~lLgTX7gNJR*;J-+JQtmx~GpJR>0@=?uf(dCmY@r*YXUTh+Po`9*1*^M8wx_{&>kv5M z&223Us4fT>3L-_C-d@w%&-Y(so)`V(Sp%=PDPRsjBb$^waf{lj2D9rDxb4|TJ{+Q; zvb({2**d>-+y*|(g=u~I7urhd4vSLU4`UT!Ja=EAIP6jx>qV6!~TP!!tGx?_dsuN#c zNM+lVk*)csZCC?*?a?CWA0p!7hzEqLAl2{}UW5oMX0!R;|wVtdJ$29m+mVMIg#VaOCbg&{z0zToV;-Y6JHf$B%l^9G806s_-kN>Png*) z*Ji*y@>fuap5a+O?S#IzAwp*XmMbsRbHn2VE_~2545Kb@ro? zr%bIk7t6N^*I!(K7SG2FZinmr#=t7ilWX4oUBfFp$l&PLGTAy3=Z%PY$XI5Zkkvnu zoA>pw2|0$=^5!1GSl?L^eO1Hr{P<4;9L$ibIIfPTwUjnO&+-2*=~0ug2sIF(&VH4J z3px+S)%b+7!@O=xjWU;@xux()V_3tm2G=bL_slaEO#)o{4$>oaRW+QC!|P~Et*DQj=V{^x6*uHC?7jK9-7*(qD!4_)<;bHe7-xi6B+&(`8>m$2A!nsp+8W6J5kix4HEB4C-f1G)2@ z(-!Drdc{#G@*X=me87Yib+mR8F)Miix@>e97deyX_g~avx1aC6H2sgH+Z~tzZuH??Uv#s zn+4N1#^)i&{cJU4_2VKSP=H<*hS3^?Ir+trz|No&B(51?h0p&>D`TfAut*w}sL0`2 zoLU$t;+C6(43V!9)v7`^i(V6c+D)O+5f1z@w4VsLe>Jh?y6_}Rgg&Kor!qNbb(Gk9 zdk1xJZ*fT|z32(>C!N(1U4aOxTRL!X9?1L4z%cUPasKk12r{q2pS5)W3ff}ZUT?lO zFO5E2iB88Q9KRQ3Wi_*;Cw%d~a&-)ZB$bdnj+Yh7-376<+7njL@**(Y2&m`OBFFqu zx@e$O7g{~Eqw7d$1JkekV{W>h(M!Qs9!tH)#g8nmT3at_`aw7V(f85QN1rh`&WN^)T>~Ax}qWM96Bl)X)z4EA7Q}Cv-eB=M`5l= z!5&`4)RC$v65t*NO-|j2Ex)_nnxfKpHt|lp zAbeG$TM>jt0R;&5Sc}(+doOQ{63!>Ml_5dG<={o2pky#c{8aX+{j+fb!l?5&l6!so zysd$fRbz5Kw=BFLb-!<`Y<-dm8`b4mGcyk=8%*z{6~i#IKfx+|UM(AsYjY|QfHLqV z2c){+3l!?L2As>?k8%Jke4Jbj`wdqrQkV7nt1Vs!it%La-jT02OJ;PI@5cgNAi)YE zKhbZXR(21af~!H{m*75Ik(K|S^}+3s#O75MGjdGmwe&kD=0kJp19R#^8sy2VI03{V zvmq1$*@6{Ip_8V{eceTCyYtNiXocuDll*Z4jA+9V@Hm z*T;3k(dXp@i;4!WM#M1J1Y;qQ+?^i<1_s+$5PFDnqSK06A!78YZb_zL+4FawwVD$+ zV@T;atF!RBPl!BhAOpH2v0DCMi52BHmS+f7zC)(JS>?FA&tyYY=A(x1NmWGFJnZljr~ zbMpan<7@sJ`R$^Kiju+3EpXrC$?-J9_Q)%zI~#ZFHU^M+vMq!qUd{W>$ja9ewL}G> zv)c317pOD$1H1-gO?su>nAXrRK+9qCz3p=8x8wPx9EjaF{x-1^Mv)*}l%RpcI-@hV zl$CU{fYhl`!KahQzW|giaiCy0vOp;7<5?1GGQ%aPfn}Gp6YR+#%tveaoSPyYmGTpZ zek{c`0|a`45lEnrjas0qsH8gju-b2J?Gbum1?h;A#s5F=zt}7mExW`d!<2M9MX1Ub zar9%?HZ+uY2N5-w;TB<3ijahZ$jnztJr{e)p+SJ))yFnC?8mF38Ogin8D@Bv4je(O zdX2rXX~svfpf6hTvCTw{(6vAX3BqcOTo2ZUWR9M3o2h zYSF(z)z)$0<-TxsG}RBZg@ahL$UTLubyU7ri5L+KZfpFI(%>`pkus>ZsR`q(n$(?b z@*2@L3)bQlpr>6!yYv9zSjPwU!^XGqCRoG8fU7N4vDG%Op95VKGtlKaKTI?%*ts_<7-HIR(Z5RoWutS^HYZv2dWa zM6~oOJG6A6O-1o$Ey|iDCacf{(s5r@mSo!35_|NJ0(4?^Y7<_z*G${JoE}=?JBhyF2Wl_x$#q!?EgGNSo z+4`z7HsI_F$PtU5Y7v>MuUkNcmuJ+rW_ODJJQ8Hj#ecCHCCa$HmU=H8Hnkgut!1ph zF{8p((VpP@=BCrA3r&J6X)rS30!+uCw-rh$3Zsp{pd%n@b;A3WeAkBIYqBbYM+acO z*s}?-|6p@|Gid+aan6i&xekkP(Eo$dHqxHQ*t*sa$}bF%=djZ1FH@eThq`4vt+7uT znO%a^O*jLpmQB5~1~#!aEL4%Ah($jsj8REeRpIe@L;DJOg}@AOk3hYj z@OTFj>J}oi@9bo3+mV1`5l|_XC5Ppw-lt^2@YBVP5>DUL5q;I(N?06W{ql*+IHsSj z&eEh5L-}Pl(uBngy4Hj9X9B8B`vl7whS>c;lPp$+AEsPJM2`FBNzh9|vqHgen4G7N<3d7f&V{WiCCp!I>Eiv#j;k5~o*{2q z60k@fl^44AOAr!VhkOYuF3C?(bG=cSG5BamJ0mP%U(5bAN|*rO+v|UU!JmDN< zr9I-G-Y>Kf$`OXJpcL26(eBekB4=&gL3`)&;%TSMm$u37>@cgQi0y(kv21wVLG4LD})&$gQAN|LPW44 zzba!}N?FmUfXj9%`2SNv1QGE@+g*)?3vD(Zh_XrrSV= z?Oydy?;P1v`7_Bj1XgALf;=9=kH<9jVe;WL0%KwUx_iu4VACv%=_(xZ!K?-s#SkQg z&~d{K$_qf0*r?0O%9kHvBC9P`tD3**jMcaKi0Z*1dg{`nbL z5%fTC4VKHz8r+N%+0e{@6^+=sjL5qrWnqvwehjUYjXTu_?i-ci+VJO-Q-`xP38)ws z=P)>Io$o?>|DttnP%hB(`b_E``6jjp3x%%~OuEwb0)zj?!{l z6=8O6a=cD|2e^G8P1Bp6(Oh|WB9_SUMFmA*-1y=Cd&7{>V^9pgPb^Ruo>bOCj;yo8ER}NY8(cjnj^K46z7|n|L zK1o0_qk?96Dfu*PViRkBQC7tw;6Wv)cSgPv$7%*A*oNVc9#4vXaI4qf7@lx%41UQs zuqh?eJtMqE!ekD|-y!K6W=P!gRUW2ULR|L)PIikE?Fm(Ye1V07{3;b5Kt9q+(^I$M zV}ZQG>QvKX3*iS_y0`&WR3_mcKgFmfewSAWta`?;LWict@B00zWjJf*ln9D&?&WQo zSkSrDUV%6$p?yIS1`l+9RTh9ul|ucyk~pt!zr;Az^@f8%mjlJ$QB`-T7Nug0B^pPX z4)(uu`L-%XYpUx!D|C{A?`^p;bktaB zm?u?a&2+KfzCj`&7qUFn9+hiup7QYqrax22X+)??4WBCp6vd!ZyP{6#Yq{a~nd7bo z*)Wy?ZiD4?1SPiogVuK`uoy_4Fpg<9b_^pZ;y5)=mLcR1r1pd6aCo3}Jjwy<{b;Br zr2sXeqzZ(sEUp^L(#<2ps#+>tG6*z3+Au!8iIeN-?nI<%BNUbtXu@D1rO|xuPSn1? zk($=8Bti~Xm{#<0yR@Kd-65vq@j*|jH@36$&Dc6?1bd5#)^p;|OxSSUHl)#_f5X&K z_#X=Z)l`Nk&9l;z6Y%-&Hm4C!T3o@5@9V1N%5&^YmwO(MCsQJ4TEa%k$%|@lP%8Z% z2?2kxIo{)SZ0Pw=^F5C*!>ovnYp_l&cYAlWIH)iYez**<+ds4wMduq_vR*&A-ku7U ziPmQTQgt}fK!Bby5JW+y#=L3nDFyJAIk(web(&!Zq9@3GFm6!(0IuW|!41ROBOp_z6;a z{xRP_;dT~sN;Z5_MAS_A<8jVNgI6?4#zF+jAL8ZxUj}qgfuZDG-=22nxnAixn8CVVA}Ivgk|lXJXI0-p5v+A-7gE+vwo^# z$qpHU%gSs&L)Gt)=#zMmjhSPvGLQBWz${@(1kR=nar~ZXBof~m>79>Mwlwatq z*TO#eiQC&YrQw>b4tcVIForu}rW+J13LH&=7J^PZFR+Z!<8t``r=`VrYLqoyoLkNd zfkMfqMbR*YH0J5nZ?r;j>v8WXQ>UJ32Ps9=j3(`V4rEZFRq{R*{9|ujGSC^`7?l7d7ml(nr(GQ`d`P{ z_a`FK*1X6x+V#x#9ear29ao!*yx~_r-pgeS5P+72(xbs z0Km1XCJbvb+9KjQ)p;i;5mo$pwOR?4HPuOXS43XlC5?oaGk%XUenUM@4)UY_jFT7k zripE6z=YB)&Y*1JgV~92!f#3p8V9l`c{K~p;%B?x!-=0qadCAYF61Ag>LG87nuu55 z^CfvAaewY#k4dqKqzW~_*?FD_^{ynB8~C2n&tF?yb0){ZQ0$wA!)03ps^DofL%?i) zmc{<8idzAlOR?H^7lmW{(4%0=5K7MWAa7zf+SE@e(kTL06=m?K!1p{PlWMt6^0~F$ z9)EYaBID==d$zM_4M8}lYoF7^Pt#Lm{aN-<>thRaYz?C+xTl2}q2eYZtoW&0?7GsT z(Fo;-&)1Dv1bWO)7?{vBxq=QWm1wP}ua=TrbqdR}e-YC(o8~$IajYeaD)R4g!c}J< zl=F3jJ4%xqoBfrl(=nO(8R^>9fMJj!4~_Tj`S+s;?;Ll(#g%)Ag3l9Sz2&*y`5Y49 z{gJWl;AEC)KB>sD$}C-^G9I0Ruc;Op1&H(8gMIb=x&4HHG?hAC=O<7ew@i#xDSwhZ z9*pptK^I}R+myGb<60KL`||b7=ymk3rIkz6dYDo`F%4mw2d?+;Zh@8iE7HYkM;b)K z)N$thZz#R#sYiHteBwk{6v~)2SJRS@PH@!5S**NJ9s=??&h;6Y;7Rr(P{Lk|h<}lJ z)%PA+l>;*>bny>PX3oojR~7@*Ld>kOAlM4Dcy?m=2(?RkXn@RqWGDHEFn$6^?*U+# ziewdxNhM@BG6VOi9)0ocgm zGau8OwFxMQ4mBa#E($17;s8u;XurzW6O#`@ZhN*%r_p+M zR%hoae0xbs>-l>1G@r8u#WSxblr8slRA!e2dd4!JYEMpf@E-FGkBjhvE_D-zde;?0 zwbweA`@^kn>v&4Cpkvse*&F0IP5O4&qgCSd=SYgVHQnqgXON?+&R+;s?V!c#xrWD~ z?E)EWL*@{OIa z%#?tfoMZ!#3W`g>KZ)|65#dH#yKUJ8g<}VjcBU&tg&{!)Z}!U>NWcRi#)`qOwMk&? zC!CMs{`8~?v**1#HD?#$rNGZLpJt{9ue4vg6b+o{ys3q0RwZ!sm9x8cQD zV;_uDhkL$aKTCPYHQz?FWlgV{{x&k3-?s^nk$Nqgjg$+PYa$l)&`1WaGPK%bb0m^D zAFaOJty#C-JGIAo+-I^hJf;m`P0u`D#U%@iXFpfg)Kt}g2km>PPHSXknctf05Bnkk zD9H#C3c&_p6gyAlR+I%)KiL3St-R7j98>Pk-))L|Sfxw-gL?-}8yHz6Exy0Vw^m(CE3@NB@uC*xC0P0A#)q5U$Tu z-URa@Fa$8r^72;;OX8=e0II4JIr7<2U^MzsMB|urWaGWSmfO1(l$JgyPcK#3Br#vN4o0| zHg!D{Q-Ty3KKgaFCTyFZ?!`=-Yo7}DlC5E&e!4(EsS*z;UuzAg*q9kp`XlLHc$@l= z(%YwL^1dtZeqU!j@Ho0AYm+37?<9dq6XV<jP@bXbm5Vs zQ`KADNCMz-y7&rxiiuYe@pBgQ2N)D~K)PB8S~gDWl{`-z=O-k?u?IbcM^KQ2&)m? zAGu3vW6!8so6ac1g(QA&zx4OmO`dOxdQaPSi?|#4X0JA2NkhI~X5qfhgz!Q4s&?OS zFG?Ep6$Xy+Gd-Uus&8r0sNvYNyWKyI2nr>f20<-)6)HQyKgm7|}-EF6~F<6^$ zPxQ)dK5Q#dXqPlK#jOg$h%fB_i-M_#e|}lS$~|hQRIEh+qF?H!VddB$2r>7mzya$n zcHGEG1WnqHQ!Je$fV=_^M(DIxM}d*Y{ZD1Y#J_`gUgVyV~(y9=hF&u2P;0|-=-N(t;0qEs9zN{>b)r{=qrq7FU~nTn><$_ zoI*HPXK-z9!MoF2t~|P0?*PfxsAZfm4AystHVe@%uiYO=e+Mn*mi!Xy1?m^0;W{gS z-JRgJtM0E}8vUx95{;F&@gqj-L0KePzqt*Rkn1H~opfBirE&@G z4;I3D7tQy@1h{HWE_iQt&>P24(RL=u`P##5eV)30D_VkAs=xM=^dj*+O2$CE*dFfY z`8}6;zDs-US}f%H_144gy-fB*AsVLY!RJ&~uPK{r5l;_ZW-%{?;Jo|5D~>XJbhy&nf!d2H#Xwv_9W? z+1lHecFLaAIS~}q7=B~%D4+^LFOIAC0jBLHpNN5~6gEViT=!Ij=IN%7)WdZ|@Mn^U zn~mmWC7d`b&v-_4`P&`FDvKxNv5N&(jyI6%XED%8{@ZTACVdYj94-YJ34xHS{dI>+ z2dcNzeG?CFiJOb~b;#FfC1<<;z?(@ zvU;@eWmf}1sm^I3hyW6))Ij6V@2@RBfZb-)PciC&vwx*ymE#vHUCFx%Q=d0cY+oEI zN^18z--HwNOBRJ}0rh5uN~@V_XMWj0P(wVH;6fZt8e~?bxgq4XU_EmCE08 znW#pA0<`OI;KBFD@z6kgX>$8yOJ>gLEQ$ca`Tw!!A&#kD4 z*bk6p;zLF?M6KCKh7|a+y?ncoWtr;!1t?V&mIcw{#O4gl-O_x1{tKH?2QqAWvc;#P z8Cm)M7mWEZJ&nhi*K|r#;Csj0+o49admOWNX(rQl|4gdpc&VdXWJ;6dJh8(@hG!W0 zaXMab7LVC}Es;a3{Y-R;`*7?qrt*{L7qmLFAxzHqvfQ1|_w6=7zAd&*Tk5qpgwA+> zjmPt_$5x1Hq&u_lElOOXXO9dAaw)f)|-AK_(P;*duJzeh^m1+(U zwyjTct1okk5BOVsbs(6XR$AWxo~rq_-ASK;;YlRNk6smn%cZ=fban|({$tj&A2el3 zQ&}a8PR@<9t5>PmZMi4iY{LdKW(mvyu=9Rxg#!%;d#!QrUu zR>7smhd3;`XSBIPlQP(h`1rd8rq_MA_LrPXl+Pf%2whKP-{K@k_T)y#LUO8{SkFIc z>z%=d5p_3=nOtO zNbcL~X44Wj?&Ucxw3bCBKNy>ing6(2LlWNfNgGrZ?C95Td89{iSnes7dF``356g@~ zW2*ULt7g@yn8de;S|-8{Cmkx{3ADdXo4Eoy?=f{o|2ptJSACJ$1ONUR7{&s{zT0Z~ zz;@k!)`eDhj>S}`Qh#9$B81pxJJd{D?}{Ze)#<%(Z%A9(94xVYZSO!dHjkh5JciOe zQf=A%+f{)-qEm*)rsKfDQ_^x*jkFnzC`Kd;QcSmUdXg@HObQ>Ft#`6x5BT~@uDN*t zi@E)PtH3^4mq0jqlB-YmUD?L1VmX|xv$BTGp^AyRGHiAA1y+EuVHm2l-=Q{Jx7O&$ zm}5mfuee!L_xQh09 zbS#G!5{PdF)G2I8jQttPD`+4oV1@n3T++O1j~9akS|uV`s$B5{7Ub2FH$$rMU;OVG ze{k+%==a`e{J%bm1jD`P|3HtOuti@M2)@kJExDw5f#Kd&hWur*B$%xFmu5?s%LLr9 zDmd|tcvr^WMTz2xV4p>mj3iw(zTg%7@w55FU=eieApsN!-#2X?$k#q>nBPUz)ZaO5 zQ-?=UC~$D`x{=UJJi8~r7VT9@VtChUxm-MZk8jH9r;aavtRbahX%dBaRfE5m>oj7l zTr(=u!%>+_Eh!F)m}hcZV~DnSoE?;@6=GOaZ1JJewuesU0qh0*u zmLx>?tK@@>Cq3E_NvVBWh2mi4ykN_5lHGU>RsqgOTib2*R{&DEyg=?#GW%9;^s{}Q zh_bc5+3VHV%s71xf5BSQZoJKNoh6Z?IBdQC3*tYshXgkE`q~ zk8=1%j%{BVzgthANlktr3zyNy$BtH-88>kF{m}n;|8m_k9#rGO#OAZ1%Z zn8VYt6e}!Mc9wcby$#tLvF<(H8wQ4LJdKrb`!v6AnKd)FrK~!OoS!E{L2oa7R-wqs?;*!WTL{L(48VAu!i`4$&?DzeH>#uFbw{BCBrW^vk45 zF`j280-Z(XR!?HQ79o|h3j-s)|I;N1745Kip*-*FBS?@_e$jBpb6RkuTB#C-a$5+i z|6qG$(XWix1WU~OENhkvuI-^AxF21A{$akHMpVv6FGo634}&U4yytF*Jj*`mnk_1; z?&C-jvN?TseC>XDS<#S-9XEJK*|SqnzpeJtgbD)rd@@fVphPYCEQ#2(-D$HRkQYNe zo*uyH4=?DtzpvUZeo8K@K-I%uXHmf_up+l zpj-HENZ|X=K^FW1G)5krCJyuAs`ZENlB9E3qPDjjaRD*h?~af;l_smDlZ)!`(0$1% zY<90As`5-tRtY_Buek0neIc)lT?6n4c!C)?&YV5P6nfuL_`0K8$Z0rVq`gz0l*eNJ+Ifdk951A zczB<~kWkj4Yg8heUOy zyMEIffQ(6vyG?x6p_OvBDT%VKZkUFOm4kKel! z8~md*=j`avCJ2qq%nTd4P?&GcY>b-=ihgL^7h|dzjb*lhlF)&V${@W-0MDaJ!S*!= zr*!U=1Mqu?n|^&){ElZ8dVSw;R7tTIRFAQ=`s8jj67VMPgSRTH)wU${uydrI?+#sK z3!sU;>1ZCip4krN(WNTD?o*^nSYo251~;Dy-tBocdis;k18pf9+|$sW-?YyzQ>)nA z%5Yu&E(M#9yDLFZys|cQLZ(i~3q_Ey>hU7vRvMnD(}9o>r@MVvG#ZKS%*@u;b7i84 zy1JljVdB%$TSi7~6*1Wyedh*d*cRuUl_%H+Kq5)ifN&VEY`a?tA!UAjW-^d2rq*(+ z{uWfAK5Q@CwZ<>>IEuf2!e8Uj1`?~Ll$^tTM;&SR_NtZufdG_L$^LeEvg!;Oq=T|# z(2+h)N@=Ox+lW|cd*&!ag+B9VH3svOUPbq(U)Ji8i#k&3Ws2Fn^08U%-dBeV=9PV3 zXv1S~H{5s@gr*!xCY^QW5$iFhCYo7_p08c0w`TEhwc5dF^9q;IT(aLeEa6z{0Q2qc z?xNv&f4uPggX!}zcaqMP~wqOu#$W zO&jL@=8}}mx9I*L&o7Kz#g1hLjF7lqwC$&S8xf=5hc^Y&Lw$pLHOn zdpeUffMA8=jWXKhtqTi(sT?!2z~PFnB�FTjj}0R{Gc}oFBYnQX7|Ec3Kjun93-IdZ$0DJS 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 literal 35115 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 diff --git a/tide/core/StatePreview.cpp b/tide/core/StatePreview.cpp index 45e243bb..9fd51f22 100644 --- a/tide/core/StatePreview.cpp +++ b/tide/core/StatePreview.cpp @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2016, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* All rights reserved. */ /* */ @@ -55,12 +55,11 @@ namespace { -static const QSize PREVIEW_IMAGE_SIZE( 512, 512 ); -static const QSize THUMBNAIL_SIZE( 128, 128 ); +const QSize PREVIEW_IMAGE_SIZE( 512, 512 ); } StatePreview::StatePreview( const QString &dcxFileName ) - : dcxFileName_( dcxFileName ) + : _dcxFileName( dcxFileName ) { } @@ -71,12 +70,12 @@ QString StatePreview::getFileExtension() QImage StatePreview::getImage() const { - return previewImage_; + return _previewImage; } QString StatePreview::previewFilename() const { - QFileInfo fileinfo( dcxFileName_ ); + QFileInfo fileinfo( _dcxFileName ); const QString extension = fileinfo.suffix().toLower(); if( extension != "dcx" ) @@ -84,7 +83,7 @@ QString StatePreview::previewFilename() const put_flog( LOG_WARN, "wrong state file extension: '%s' for session: '%s'" "(expected: .dcx)", extension.toLocal8Bit().constData( ), - dcxFileName_.toLocal8Bit().constData( )); + _dcxFileName.toLocal8Bit().constData( )); return QString(); } return fileinfo.path() + "/" + fileinfo.completeBaseName() + getFileExtension(); @@ -117,7 +116,8 @@ void StatePreview::generateImage( const QSize& wallDimensions, const QString& filename = window->getContent()->getURI(); ThumbnailGeneratorPtr generator = - ThumbnailGeneratorFactory::getGenerator( filename, THUMBNAIL_SIZE ); + ThumbnailGeneratorFactory::getGenerator( filename, + area.size().toSize( )); const QImage image = generator->generate( filename ); painter.drawImage( area, image ); @@ -125,12 +125,12 @@ void StatePreview::generateImage( const QSize& wallDimensions, painter.end(); - previewImage_ = preview; + _previewImage = preview; } bool StatePreview::saveToFile() const { - const bool success = previewImage_.save( previewFilename(), "PNG" ); + const bool success = _previewImage.save( previewFilename(), "PNG" ); if( !success ) put_flog( LOG_ERROR, "Saving StatePreview image failed: '%s'", @@ -142,9 +142,5 @@ bool StatePreview::saveToFile() const bool StatePreview::loadFromFile() { QImageReader reader( previewFilename( )); - if ( reader.canRead( )) - { - return reader.read( &previewImage_ ); - } - return false; + return reader.canRead() && reader.read( &_previewImage ); } diff --git a/tide/core/StatePreview.h b/tide/core/StatePreview.h index e933ee07..d53b79e4 100644 --- a/tide/core/StatePreview.h +++ b/tide/core/StatePreview.h @@ -1,5 +1,5 @@ /*********************************************************************/ -/* Copyright (c) 2013, EPFL/Blue Brain Project */ +/* Copyright (c) 2013-2016, EPFL/Blue Brain Project */ /* Raphael Dumusc */ /* All rights reserved. */ /* */ @@ -96,8 +96,8 @@ class StatePreview protected: QString previewFilename() const; - QString dcxFileName_; - QImage previewImage_; + QString _dcxFileName; + QImage _previewImage; }; #endif // STATEPREVIEW_H diff --git a/tide/core/thumbnail/FolderThumbnailGenerator.cpp b/tide/core/thumbnail/FolderThumbnailGenerator.cpp index bb580827..f8c2d5d7 100644 --- a/tide/core/thumbnail/FolderThumbnailGenerator.cpp +++ b/tide/core/thumbnail/FolderThumbnailGenerator.cpp @@ -70,30 +70,20 @@ QImage FolderThumbnailGenerator::generate( const QString& filename ) const return createErrorImage( "folder" ); } -QVector -FolderThumbnailGenerator::_calculatePlacement( int nX, int nY, float padding, - float totalWidth, - float totalHeight ) const +QImage +FolderThumbnailGenerator::_createFolderImage( const QDir& dir, + const bool generateThumbnails ) const { - const float totalPaddingWidth = padding*(nX+1); - const float imageWidth = (1.0f-totalPaddingWidth)/(float)nX; + QImage img = createGradientImage( Qt::black, Qt::white ); - const float totalPaddingHeight = padding*(nY+1); - const float imageHeight = (1.0f-totalPaddingHeight)/(float)nY; + const QFileInfoList& fileList = _getSupportedFilesInDir( dir ); - QVector rect; - for( int j = 0; j < nY; ++j ) - { - const float y = padding + j*(imageHeight+padding); - for( int i = 0; i < nX; ++i ) - { - const float x = padding + i*(imageWidth+padding); - rect.append( QRect( x*totalWidth, y*totalHeight, - imageWidth*totalWidth, - imageHeight*totalHeight )); - } - } - return rect; + if( generateThumbnails && fileList.size() > 0 ) + _paintThumbnailsMosaic( img, fileList ); + else + paintText( img, FOLDER_TEXT ); + + return img; } void FolderThumbnailGenerator::_paintThumbnailsMosaic( QImage& img, @@ -106,10 +96,10 @@ void FolderThumbnailGenerator::_paintThumbnailsMosaic( QImage& img, return; QVector rect = _calculatePlacement( FOLDER_THUMBNAILS_X, - FOLDER_THUMBNAILS_Y, - FOLDER_THUMBNAILS_PADDING, - img.size().width(), - img.size().height( )); + FOLDER_THUMBNAILS_Y, + FOLDER_THUMBNAILS_PADDING, + img.size().width(), + img.size().height( )); QPainter painter( &img ); for( int i = 0; i < numPreviews; ++i ) { @@ -121,27 +111,47 @@ void FolderThumbnailGenerator::_paintThumbnailsMosaic( QImage& img, if( QDir( filename ).exists( )) thumbnail = _createFolderImage( QDir( filename ), false ); else - thumbnail = ThumbnailGeneratorFactory::getGenerator( filename, _size )->generate( filename ); + { + const auto size = rect[i].size().toSize(); + auto generator = + ThumbnailGeneratorFactory::getGenerator( filename, size ); + thumbnail = generator->generate( filename ); + } - painter.drawImage( rect[i], thumbnail ); + // Draw the thumbnail centered in its rectangle, preserving aspect ratio + QSizeF paintedSize( thumbnail.size( )); + paintedSize.scale( rect[i].size(), Qt::KeepAspectRatio ); + QRectF paintRect( QPointF(), paintedSize ); + paintRect.moveCenter( rect[i].center( )); + painter.drawImage( paintRect, thumbnail ); } painter.end(); } -QImage -FolderThumbnailGenerator::_createFolderImage( const QDir& dir, - const bool generateThumbnails ) const +QVector +FolderThumbnailGenerator::_calculatePlacement( int nX, int nY, float padding, + float totalWidth, + float totalHeight ) const { - QImage img = createGradientImage( Qt::black, Qt::white ); - - const QFileInfoList& fileList = _getSupportedFilesInDir( dir ); + const float totalPaddingWidth = padding*(nX+1); + const float imageWidth = (1.0f-totalPaddingWidth)/(float)nX; - if( generateThumbnails && fileList.size() > 0 ) - _paintThumbnailsMosaic(img, fileList); - else - paintText( img, FOLDER_TEXT ); + const float totalPaddingHeight = padding*(nY+1); + const float imageHeight = (1.0f-totalPaddingHeight)/(float)nY; - return img; + QVector rect; + for( int j = 0; j < nY; ++j ) + { + const float y = padding + j*(imageHeight+padding); + for( int i = 0; i < nX; ++i ) + { + const float x = padding + i*(imageWidth+padding); + rect.append( QRect( x*totalWidth, y*totalHeight, + imageWidth*totalWidth, + imageHeight*totalHeight )); + } + } + return rect; } QFileInfoList diff --git a/tide/core/thumbnail/PDFThumbnailGenerator.cpp b/tide/core/thumbnail/PDFThumbnailGenerator.cpp index e3f66a80..0ac8be55 100644 --- a/tide/core/thumbnail/PDFThumbnailGenerator.cpp +++ b/tide/core/thumbnail/PDFThumbnailGenerator.cpp @@ -70,8 +70,8 @@ QImage PDFThumbnailGenerator::generate( const QString& filename ) const if( QFileInfo( filename ).size() > maxPdfPageSize * pdf.getPageCount( )) return _createLargePdfPlaceholder(); - const QImage image = pdf.renderToImage( _size ); - + const QSize imageSize = pdf.getSize().scaled( _size, _aspectRatioMode ); + const QImage image = pdf.renderToImage( imageSize ); if( image.isNull( )) { put_flog( LOG_ERROR, "could not render pdf file: '%s'", diff --git a/tide/core/thumbnail/ThumbnailGenerator.cpp b/tide/core/thumbnail/ThumbnailGenerator.cpp index 3b177fc6..33a711a6 100644 --- a/tide/core/thumbnail/ThumbnailGenerator.cpp +++ b/tide/core/thumbnail/ThumbnailGenerator.cpp @@ -48,12 +48,9 @@ #define THUMBNAIL_FONT_SIZE 30 -// TODO change this when the slide show is adapted to keep aspect ratio -#define ASPECT_RATIO Qt::IgnoreAspectRatio - ThumbnailGenerator::ThumbnailGenerator( const QSize& size ) : _size( size ) - , _aspectRatioMode( ASPECT_RATIO ) + , _aspectRatioMode( Qt::KeepAspectRatio ) { }