HaikuDepot: Icon / Tarball Handling

Instead of exploding the tar-ball of icons from
HDS, keep it as a tar-ball, index it and read
data directly out from specific indicies on demand.

This will speed up the process of downloading
the icons by removing the unpack.  Also updates
will be faster by avoiding the need to delete the
old icon files.

Because icons are loaded on-demand, the start
time is faster by avoiding all the icon loads.
There are also savings on memory consumption.

Indexing on each load is surprisingly fast so
no external index is maintained.  Likewise for
the tar-balls's meta-data.

This commit does not cover the implementation
of an LRU cache of the icons in memory.

Relates to #15370

Change-Id: Ia1647d8c805be89618f493d2592bf7877fca3f14
Reviewed-on: https://review.haiku-os.org/c/haiku/+/3205
Reviewed-by: Adrien Destugues <[email protected]>
This commit is contained in:
Andrew Lindesay
2020-09-12 23:06:24 +00:00
parent 2ad62d391b
commit f0e491d390
50 changed files with 2513 additions and 949 deletions
@@ -27,6 +27,14 @@ enum {
MSG_LOG_OUT = 'lgot', MSG_LOG_OUT = 'lgot',
}; };
enum BitmapSize {
BITMAP_SIZE_16 = 1,
BITMAP_SIZE_22 = 2,
BITMAP_SIZE_32 = 3,
BITMAP_SIZE_64 = 4,
BITMAP_SIZE_ANY = 5
};
// when somebody rates a package, there is a numerical // when somebody rates a package, there is a numerical
// rating which is expressed in a float 0 --> 5. This // rating which is expressed in a float 0 --> 5. This
// is visualized by a series of colored stars. These // is visualized by a series of colored stars. These
+2 -1
View File
@@ -119,8 +119,8 @@ local applicationSources =
DecisionProvider.cpp DecisionProvider.cpp
FeaturedPackagesView.cpp FeaturedPackagesView.cpp
FilterView.cpp FilterView.cpp
IconTarPtr.cpp
JobStateListener.cpp JobStateListener.cpp
LocalIconStore.cpp
LanguageModel.cpp LanguageModel.cpp
LinkView.cpp LinkView.cpp
LinkedBitmapView.cpp LinkedBitmapView.cpp
@@ -133,6 +133,7 @@ local applicationSources =
PackageAction.cpp PackageAction.cpp
PackageActionHandler.cpp PackageActionHandler.cpp
PackageContentsView.cpp PackageContentsView.cpp
PackageIconTarRepository.cpp
PackageInfo.cpp PackageInfo.cpp
PackageInfoListener.cpp PackageInfoListener.cpp
PackageInfoView.cpp PackageInfoView.cpp
+48
View File
@@ -0,0 +1,48 @@
/*
* Copyright 2020, Andrew Lindesay <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "IconTarPtr.h"
IconTarPtr::IconTarPtr(const BString& name)
:
fName(name),
fOffsetsMask(0)
{
}
IconTarPtr::~IconTarPtr()
{
}
const BString&
IconTarPtr::Name() const
{
return fName;
}
off_t
IconTarPtr::Offset(BitmapSize size) const
{
return fOffsets[size];
}
bool
IconTarPtr::HasOffset(BitmapSize size) const
{
return 0 != (fOffsetsMask & (1 << size));
}
void
IconTarPtr::SetOffset(BitmapSize size, off_t value)
{
fOffsets[size] = value;
fOffsetsMask |= (1 << size);
}
+38
View File
@@ -0,0 +1,38 @@
/*
* Copyright 2020, Andrew Lindesay <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef ICON_TAR_PTR_H
#define ICON_TAR_PTR_H
#include <stdlib.h>
#include <Referenceable.h>
#include <String.h>
#include "HaikuDepotConstants.h"
/*! The tar icon repository is able to find the icons for each package by
scanning the tar file for suitable icon files and recording the offsets into
the tar file when it does find a suitable icon file. This class is used
to return the offsets for a given package.
*/
class IconTarPtr : public BReferenceable {
public:
IconTarPtr(const BString& name);
virtual ~IconTarPtr();
const BString& Name() const;
bool HasOffset(BitmapSize size) const;
off_t Offset(BitmapSize size) const;
void SetOffset(BitmapSize size, off_t value);
private:
BString fName;
uint8 fOffsetsMask;
off_t fOffsets[5];
};
#endif // ICON_TAR_PTR_H
@@ -1,97 +0,0 @@
/*
* Copyright 2017-2020, Andrew Lindesay <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "LocalIconStore.h"
#include <stdio.h>
#include <Directory.h>
#include <FindDirectory.h>
#include "Logger.h"
#include "ServerIconExportUpdateProcess.h"
#include "StorageUtils.h"
LocalIconStore::LocalIconStore(const BPath& path)
{
fIconStoragePath = path;
}
LocalIconStore::~LocalIconStore()
{
}
bool
LocalIconStore::_HasIconStoragePath() const
{
return fIconStoragePath.InitCheck() == B_OK;
}
/* This method will try to find an icon for the package name supplied. If an
* icon was able to be found then the method will return B_OK and will update
* the supplied path object with the path to the icon file.
*/
status_t
LocalIconStore::TryFindIconPath(const BString& pkgName, BPath& path) const
{
BPath bestIconPath;
BPath iconPkgPath(fIconStoragePath);
bool exists;
bool isDir;
if ( (iconPkgPath.Append("hicn") == B_OK)
&& (iconPkgPath.Append(pkgName) == B_OK)
&& (StorageUtils::ExistsObject(iconPkgPath, &exists, &isDir, NULL)
== B_OK)
&& exists
&& isDir
&& (_IdentifyBestIconFileAtDirectory(iconPkgPath, bestIconPath)
== B_OK)
) {
path = bestIconPath;
return B_OK;
}
path.Unset();
return B_FILE_NOT_FOUND;
}
status_t
LocalIconStore::_IdentifyBestIconFileAtDirectory(const BPath& directory,
BPath& bestIconPath) const
{
static const char* kIconLeafnames[] = {
"icon.hvif",
"64.png",
"32.png",
"16.png",
NULL
};
bestIconPath.Unset();
for (int32 i = 0; kIconLeafnames[i] != NULL; i++) {
BPath workingPath(directory);
bool exists;
bool isDir;
if ( (workingPath.Append(kIconLeafnames[i]) == B_OK
&& StorageUtils::ExistsObject(
workingPath, &exists, &isDir, NULL) == B_OK)
&& exists
&& !isDir) {
bestIconPath.SetTo(workingPath.Path());
return B_OK;
}
}
return B_FILE_NOT_FOUND;
}
@@ -1,33 +0,0 @@
/*
* Copyright 2017, Andrew Lindesay <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef LOCAL_ICON_STORE_H
#define LOCAL_ICON_STORE_H
#include <String.h>
#include <File.h>
#include <Path.h>
#include "PackageInfo.h"
class LocalIconStore {
public:
LocalIconStore(const BPath& path);
virtual ~LocalIconStore();
status_t TryFindIconPath(const BString& pkgName,
BPath& path) const;
private:
bool _HasIconStoragePath() const;
status_t _IdentifyBestIconFileAtDirectory(
const BPath& directory,
BPath& bestIconPath) const;
BPath fIconStoragePath;
};
#endif // LOCAL_ICON_STORE_H
+20 -2
View File
@@ -341,6 +341,24 @@ Model::Language()
} }
PackageIconRepository&
Model::GetPackageIconRepository()
{
return fPackageIconRepository;
}
status_t
Model::InitPackageIconRepository()
{
BPath tarPath;
status_t result = IconTarPath(tarPath);
if (result == B_OK)
result = fPackageIconRepository.Init(tarPath);
return result;
}
bool bool
Model::AddListener(const ModelListenerRef& listener) Model::AddListener(const ModelListenerRef& listener)
{ {
@@ -906,9 +924,9 @@ Model::DumpExportReferenceDataPath(BPath& path)
status_t status_t
Model::IconStoragePath(BPath& path) const Model::IconTarPath(BPath& path) const
{ {
return StorageUtils::LocalWorkingDirectoryPath("__allicons", path); return StorageUtils::LocalWorkingFilesPath("pkgicon-all.tar", path);
} }
+7 -2
View File
@@ -9,8 +9,8 @@
#include <Locker.h> #include <Locker.h>
#include "AbstractProcess.h" #include "AbstractProcess.h"
#include "PackageIconTarRepository.h"
#include "LanguageModel.h" #include "LanguageModel.h"
#include "LocalIconStore.h"
#include "PackageInfo.h" #include "PackageInfo.h"
#include "WebAppInterface.h" #include "WebAppInterface.h"
@@ -71,6 +71,9 @@ public:
virtual ~Model(); virtual ~Model();
LanguageModel* Language(); LanguageModel* Language();
PackageIconRepository&
GetPackageIconRepository();
status_t InitPackageIconRepository();
BLocker* Lock() BLocker* Lock()
{ return &fLock; } { return &fLock; }
@@ -152,7 +155,7 @@ public:
DepotMapper* depotMapper, DepotMapper* depotMapper,
void* context); void* context);
status_t IconStoragePath(BPath& path) const; status_t IconTarPath(BPath& path) const;
status_t DumpExportReferenceDataPath(BPath& path); status_t DumpExportReferenceDataPath(BPath& path);
status_t DumpExportRepositoryDataPath(BPath& path); status_t DumpExportRepositoryDataPath(BPath& path);
status_t DumpExportPkgDataPath(BPath& path, status_t DumpExportPkgDataPath(BPath& path,
@@ -206,6 +209,8 @@ private:
bool fShowDevelopPackages; bool fShowDevelopPackages;
LanguageModel fLanguageModel; LanguageModel fLanguageModel;
PackageIconTarRepository
fPackageIconRepository;
WebAppInterface fWebAppInterface; WebAppInterface fWebAppInterface;
ModelListenerList fListeners; ModelListenerList fListeners;
@@ -0,0 +1,22 @@
/*
* Copyright 2020, Andrew Lindesay <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef PACKAGE_ICON_REPOSITORY_H
#define PACKAGE_ICON_REPOSITORY_H
#include <String.h>
#include "HaikuDepotConstants.h"
#include "SharedBitmap.h"
class PackageIconRepository {
public:
virtual bool HasAnyIcon(const BString& pkgName) = 0;
virtual status_t GetIcon(const BString& pkgName, BitmapSize size,
BitmapRef& bitmap) = 0;
};
#endif // PACKAGE_ICON_REPOSITORY_H
@@ -0,0 +1,371 @@
/*
* Copyright 2020, Andrew Lindesay <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "PackageIconTarRepository.h"
#include <Autolock.h>
#include <AutoDeleter.h>
#include <File.h>
#include <support/StopWatch.h>
#include "Logger.h"
#include "TarArchiveService.h"
BitmapRef
PackageIconTarRepository::sDefaultIcon(new(std::nothrow) SharedBitmap(
"application/x-vnd.haiku-package"), true);
/*! An instance of this class can be provided to the TarArchiveService to
be called each time a tar entry is found. This way it is able to capture
the offsets of the icons in the tar file against the package names.
*/
class IconTarPtrEntryListener : public TarEntryListener
{
public:
IconTarPtrEntryListener(
PackageIconTarRepository*
fPackageIconTarRepository);
virtual ~IconTarPtrEntryListener();
virtual status_t Handle(
const TarArchiveHeader& header,
size_t offset,
BDataIO *data);
private:
status_t _LeafNameToBitmapSize(BString& leafName,
BitmapSize* bitmapSize);
private:
PackageIconTarRepository*
fPackageIconTarRepository;
};
IconTarPtrEntryListener::IconTarPtrEntryListener(
PackageIconTarRepository* packageIconTarRepository)
:
fPackageIconTarRepository(packageIconTarRepository)
{
}
IconTarPtrEntryListener::~IconTarPtrEntryListener()
{
}
/*! The format of the filenames in the archive are of the format;
\code
hicn/ardino/icon.hvif
\endcode
The leafname (the last part of the path) determines the type of the file as
it could be either in HVIF format or a PNG of various sizes.
*/
status_t
IconTarPtrEntryListener::Handle(const TarArchiveHeader& header,
size_t offset, BDataIO *data)
{
if (header.FileType() != TAR_FILE_TYPE_NORMAL)
return B_OK;
BString fileName = header.FileName();
if (!fileName.StartsWith("hicn/"))
return B_OK;
int32 secondSlashIdx = fileName.FindFirst("/", 5);
if (secondSlashIdx == B_ERROR || secondSlashIdx == 5)
return B_OK;
BString packageName;
BString leafName;
fileName.CopyInto(packageName, 5, secondSlashIdx - 5);
fileName.CopyInto(leafName, secondSlashIdx + 1,
fileName.Length() - (secondSlashIdx + 1));
BitmapSize bitmapSize;
if (_LeafNameToBitmapSize(leafName, &bitmapSize) == B_OK) {
fPackageIconTarRepository->AddIconTarPtr(packageName, bitmapSize,
offset);
}
return B_OK;
}
status_t
IconTarPtrEntryListener::_LeafNameToBitmapSize(BString& leafName,
BitmapSize* bitmapSize)
{
if (leafName == "icon.hvif") {
*bitmapSize = BITMAP_SIZE_ANY;
return B_OK;
}
if (leafName == "64.png") {
*bitmapSize = BITMAP_SIZE_64;
return B_OK;
}
if (leafName == "32.png") {
*bitmapSize = BITMAP_SIZE_32;
return B_OK;
}
if (leafName == "16.png") {
*bitmapSize = BITMAP_SIZE_16;
return B_OK;
}
return B_BAD_VALUE;
}
PackageIconTarRepository::PackageIconTarRepository()
:
fTarIo(NULL)
{
}
PackageIconTarRepository::~PackageIconTarRepository()
{
}
/*! This method will reconfigure itself using the data in the tar file supplied.
Any existing data will be flushed and the new tar will be scanned for
offsets to usable files.
*/
status_t
PackageIconTarRepository::Init(BPath& tarPath)
{
BAutolock locker(&fLock);
_Close();
status_t result = B_OK;
if (tarPath.Path() == NULL) {
HDINFO("empty path to tar-ball");
result = B_BAD_VALUE;
}
BFile *tarIo = NULL;
if (result == B_OK) {
HDINFO("will init icon model from tar [%s]", tarPath.Path());
tarIo = new BFile(tarPath.Path(), O_RDONLY);
if (!tarIo->IsReadable()) {
HDERROR("unable to read the tar [%s]", tarPath.Path());
result = B_IO_ERROR;
}
}
// will fill the model up with records from the tar-ball.
if (result == B_OK) {
BStopWatch watch("PackageIconTarRepository::Init", true);
HDINFO("will read [%s] and collect the tar pointers", tarPath.Path());
IconTarPtrEntryListener* listener = new IconTarPtrEntryListener(this);
ObjectDeleter<IconTarPtrEntryListener> listenerDeleter(listener);
TarArchiveService::ForEachEntry(*tarIo, listener);
double secs = watch.ElapsedTime() / 1000000.0;
HDINFO("did collect %" B_PRIi32 " tar pointers (%6.3g secs)",
fIconTarPtrs.Size(), secs);
}
if (result == B_OK)
fTarIo = tarIo;
else
delete tarIo;
return result;
}
void
PackageIconTarRepository::_Close()
{
delete fTarIo;
fTarIo = NULL;
fIconTarPtrs.Clear();
fIconCache.Clear();
}
/*! This method should be treated private and only called from a situation
in which the class's lock is acquired. It is used to populate data from
the parsing of the tar headers. It is called from the listener above.
*/
void
PackageIconTarRepository::AddIconTarPtr(const BString& packageName,
BitmapSize bitmapSize, off_t offset)
{
IconTarPtrRef tarPtrRef = _GetOrCreateIconTarPtr(packageName);
tarPtrRef->SetOffset(bitmapSize, offset);
}
bool
PackageIconTarRepository::HasAnyIcon(const BString& pkgName)
{
BAutolock locker(&fLock);
HashString key(pkgName);
return fIconTarPtrs.ContainsKey(key);
}
status_t
PackageIconTarRepository::GetIcon(const BString& pkgName, BitmapSize size,
BitmapRef& bitmap)
{
BAutolock locker(&fLock);
status_t result = B_OK;
BitmapSize actualSize;
off_t iconDataTarOffset = -1;
const IconTarPtrRef tarPtrRef = _GetIconTarPtr(pkgName);
if (tarPtrRef.Get() != NULL) {
iconDataTarOffset = _OffsetToBestRepresentation(tarPtrRef, size,
&actualSize);
}
if (iconDataTarOffset < 0)
bitmap.SetTo(sDefaultIcon);
else {
HashString key = _ToIconCacheKey(pkgName, actualSize);
// TODO; need to implement an LRU cache so that not too many icons are
// in memory at the same time.
if (!fIconCache.ContainsKey(key)) {
result = _CreateIconFromTarOffset(iconDataTarOffset, bitmap);
if (result == B_OK)
fIconCache.Put(key, bitmap);
else {
HDERROR("failure to read image for package [%s] at offset %"
B_PRIdSSIZE, pkgName.String(), iconDataTarOffset);
fIconCache.Put(key, sDefaultIcon);
}
}
bitmap.SetTo(fIconCache.Get(key).Get());
}
return result;
}
IconTarPtrRef
PackageIconTarRepository::_GetIconTarPtr(const BString& pkgName) const
{
return fIconTarPtrs.Get(HashString(pkgName));
}
const char*
PackageIconTarRepository::_ToIconCacheKeySuffix(BitmapSize size)
{
switch (size)
{
case BITMAP_SIZE_16:
return "16";
// note that size 22 is not supported.
case BITMAP_SIZE_32:
return "32";
case BITMAP_SIZE_64:
return "64";
case BITMAP_SIZE_ANY:
return "any";
default:
HDERROR("unsupported bitmap size");
exit(1);
break;
}
}
const HashString
PackageIconTarRepository::_ToIconCacheKey(const BString& pkgName,
BitmapSize size)
{
return HashString(BString(pkgName) << "__x" << _ToIconCacheKeySuffix(size));
}
status_t
PackageIconTarRepository::_CreateIconFromTarOffset(off_t offset,
BitmapRef& bitmap)
{
fTarIo->Seek(offset, SEEK_SET);
TarArchiveHeader header;
status_t result = TarArchiveService::GetEntry(*fTarIo, header);
if (result == B_OK && header.Length() <= 0)
result = B_BAD_DATA;
if (result == B_OK)
bitmap.SetTo(new(std::nothrow)SharedBitmap(*fTarIo, header.Length()));
return result;
}
/*! If there is a vector representation (HVIF) then this will be the best
option. If there are only bitmap images to choose from then consider what
the target size is and choose the best image to match.
*/
/*static*/ off_t
PackageIconTarRepository::_OffsetToBestRepresentation(
const IconTarPtrRef iconTarPtrRef, BitmapSize desiredSize,
BitmapSize* actualSize)
{
if (iconTarPtrRef->HasOffset(BITMAP_SIZE_ANY)) {
*actualSize = BITMAP_SIZE_ANY;
return iconTarPtrRef->Offset(BITMAP_SIZE_ANY);
}
if (iconTarPtrRef->HasOffset(BITMAP_SIZE_64)
&& desiredSize >= BITMAP_SIZE_64) {
*actualSize = BITMAP_SIZE_64;
return iconTarPtrRef->Offset(BITMAP_SIZE_64);
}
if (iconTarPtrRef->HasOffset(BITMAP_SIZE_32)
&& desiredSize >= BITMAP_SIZE_32) {
*actualSize = BITMAP_SIZE_32;
return iconTarPtrRef->Offset(BITMAP_SIZE_32);
}
if (iconTarPtrRef->HasOffset(BITMAP_SIZE_22)
&& desiredSize >= BITMAP_SIZE_22) {
*actualSize = BITMAP_SIZE_22;
return iconTarPtrRef->Offset(BITMAP_SIZE_22);
}
if (iconTarPtrRef->HasOffset(BITMAP_SIZE_16)) {
*actualSize = BITMAP_SIZE_16;
return iconTarPtrRef->Offset(BITMAP_SIZE_16);
}
return -1;
}
IconTarPtrRef
PackageIconTarRepository::_GetOrCreateIconTarPtr(const BString& pkgName)
{
BAutolock locker(&fLock);
HashString key(pkgName);
if (!fIconTarPtrs.ContainsKey(key)) {
IconTarPtrRef value(new IconTarPtr(pkgName));
fIconTarPtrs.Put(key, value);
return value;
}
return fIconTarPtrs.Get(key);
}
/*static*/ void
PackageIconTarRepository::CleanupDefaultIcon()
{
sDefaultIcon.Unset();
}
@@ -0,0 +1,65 @@
/*
* Copyright 2020, Andrew Lindesay <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef PACKAGE_ICON_TAR_REPOSITORY_H
#define PACKAGE_ICON_TAR_REPOSITORY_H
#include <DataIO.h>
#include <HashMap.h>
#include <HashString.h>
#include <Locker.h>
#include <Path.h>
#include <Referenceable.h>
#include "PackageIconRepository.h"
#include "IconTarPtr.h"
typedef BReference<IconTarPtr> IconTarPtrRef;
class PackageIconTarRepository : public PackageIconRepository {
public:
PackageIconTarRepository();
virtual ~PackageIconTarRepository();
status_t Init(BPath& tarPath);
void AddIconTarPtr(const BString& pkgName,
BitmapSize size, off_t offset);
virtual status_t GetIcon(const BString& pkgName, BitmapSize size,
BitmapRef& bitmap);
virtual bool HasAnyIcon(const BString& pkgName);
static void CleanupDefaultIcon();
private:
void _Close();
const char* _ToIconCacheKeySuffix(BitmapSize size);
const HashString _ToIconCacheKey(const BString& pkgName,
BitmapSize size);
IconTarPtrRef _GetOrCreateIconTarPtr(const BString& pkgName);
IconTarPtrRef _GetIconTarPtr(const BString& pkgName) const;
status_t _CreateIconFromTarOffset(off_t offset,
BitmapRef& bitmap);
static off_t _OffsetToBestRepresentation(
const IconTarPtrRef iconTarPtrRef,
BitmapSize desiredSize,
BitmapSize* actualSize);
private:
BLocker fLock;
BPositionIO* fTarIo;
HashMap<HashString, BitmapRef>
fIconCache;
HashMap<HashString, IconTarPtrRef>
fIconTarPtrs;
static BitmapRef sDefaultIcon;
};
#endif // PACKAGE_ICON_TAR_REPOSITORY_H
+3 -24
View File
@@ -456,14 +456,8 @@ ScreenshotInfo::operator!=(const ScreenshotInfo& other) const
// #pragma mark - PackageInfo // #pragma mark - PackageInfo
BitmapRef
PackageInfo::sDefaultIcon(new(std::nothrow) SharedBitmap(
"application/x-vnd.haiku-package"), true);
PackageInfo::PackageInfo() PackageInfo::PackageInfo()
: :
fIcon(sDefaultIcon),
fName(), fName(),
fTitle(), fTitle(),
fVersion(), fVersion(),
@@ -494,7 +488,6 @@ PackageInfo::PackageInfo()
PackageInfo::PackageInfo(const BPackageInfo& info) PackageInfo::PackageInfo(const BPackageInfo& info)
: :
fIcon(sDefaultIcon),
fName(info.Name()), fName(info.Name()),
fTitle(), fTitle(),
fVersion(info.Version()), fVersion(info.Version()),
@@ -541,7 +534,6 @@ PackageInfo::PackageInfo(const BString& name,
const BString& shortDescription, const BString& fullDescription, const BString& shortDescription, const BString& fullDescription,
int32 flags, const char* architecture) int32 flags, const char* architecture)
: :
fIcon(sDefaultIcon),
fName(name), fName(name),
fTitle(), fTitle(),
fVersion(version), fVersion(version),
@@ -573,7 +565,6 @@ PackageInfo::PackageInfo(const BString& name,
PackageInfo::PackageInfo(const PackageInfo& other) PackageInfo::PackageInfo(const PackageInfo& other)
: :
fIcon(other.fIcon),
fName(other.fName), fName(other.fName),
fTitle(other.fTitle), fTitle(other.fTitle),
fVersion(other.fVersion), fVersion(other.fVersion),
@@ -607,7 +598,6 @@ PackageInfo::PackageInfo(const PackageInfo& other)
PackageInfo& PackageInfo&
PackageInfo::operator=(const PackageInfo& other) PackageInfo::operator=(const PackageInfo& other)
{ {
fIcon = other.fIcon;
fName = other.fName; fName = other.fName;
fTitle = other.fTitle; fTitle = other.fTitle;
fVersion = other.fVersion; fVersion = other.fVersion;
@@ -639,8 +629,7 @@ PackageInfo::operator=(const PackageInfo& other)
bool bool
PackageInfo::operator==(const PackageInfo& other) const PackageInfo::operator==(const PackageInfo& other) const
{ {
return fIcon == other.fIcon return fName == other.fName
&& fName == other.fName
&& fTitle == other.fTitle && fTitle == other.fTitle
&& fVersion == other.fVersion && fVersion == other.fVersion
&& fPublisher == other.fPublisher && fPublisher == other.fPublisher
@@ -709,16 +698,6 @@ PackageInfo::SetFullDescription(const BString& description)
} }
void
PackageInfo::SetIcon(const BitmapRef& icon)
{
if (fIcon != icon) {
fIcon = icon;
_NotifyListeners(PKG_CHANGED_ICON);
}
}
void void
PackageInfo::SetHasChangelog(bool value) PackageInfo::SetHasChangelog(bool value)
{ {
@@ -991,9 +970,9 @@ PackageInfo::RemoveListener(const PackageInfoListenerRef& listener)
void void
PackageInfo::CleanupDefaultIcon() PackageInfo::NotifyChangedIcon()
{ {
sDefaultIcon.Unset(); _NotifyListeners(PKG_CHANGED_ICON);
} }
+1 -9
View File
@@ -283,10 +283,6 @@ public:
const PublisherInfo& Publisher() const const PublisherInfo& Publisher() const
{ return fPublisher; } { return fPublisher; }
void SetIcon(const BitmapRef& icon);
const BitmapRef& Icon() const
{ return fIcon; }
void SetHasChangelog(bool value); void SetHasChangelog(bool value);
bool HasChangelog() const bool HasChangelog() const
{ return fHasChangelog; } { return fHasChangelog; }
@@ -367,17 +363,15 @@ public:
void RemoveListener( void RemoveListener(
const PackageInfoListenerRef& listener); const PackageInfoListenerRef& listener);
static void CleanupDefaultIcon();
void StartCollatingChanges(); void StartCollatingChanges();
void EndCollatingChanges(); void EndCollatingChanges();
void NotifyChangedIcon();
private: private:
void _NotifyListeners(uint32 changes); void _NotifyListeners(uint32 changes);
void _NotifyListenersImmediate(uint32 changes); void _NotifyListenersImmediate(uint32 changes);
private: private:
BitmapRef fIcon;
BString fName; BString fName;
BString fTitle; BString fTitle;
BPackageVersion fVersion; BPackageVersion fVersion;
@@ -407,8 +401,6 @@ private:
bool fIsCollatingChanges; bool fIsCollatingChanges;
uint32 fCollatedChanges; uint32 fCollatedChanges;
static BitmapRef sDefaultIcon;
}; };
@@ -17,6 +17,7 @@
#include <support/ZlibCompressionAlgorithm.h> #include <support/ZlibCompressionAlgorithm.h>
#include "DataIOUtils.h"
#include "HaikuDepotConstants.h" #include "HaikuDepotConstants.h"
#include "Logger.h" #include "Logger.h"
#include "ServerHelper.h" #include "ServerHelper.h"
@@ -112,16 +113,9 @@ AbstractServerProcess::IfModifiedSinceHeaderValue(BString& headerValue,
StandardMetaData metaData; StandardMetaData metaData;
status_t result = PopulateMetaData(metaData, metaDataPath, jsonPath); status_t result = PopulateMetaData(metaData, metaDataPath, jsonPath);
if (result == B_OK) { if (result == B_OK)
SetIfModifiedSinceHeaderValueFromMetaData(headerValue, metaData);
// An example of this output would be; 'Fri, 24 Oct 2014 19:32:27 +0000' else {
BDateTime modifiedDateTime = metaData
.GetDataModifiedTimestampAsDateTime();
BPrivate::BHttpTime modifiedHttpTime(modifiedDateTime);
headerValue.SetTo(modifiedHttpTime
.ToString(BPrivate::B_HTTP_TIME_FORMAT_COOKIE));
} else {
HDERROR("unable to parse the meta-data date and time from [%s]" HDERROR("unable to parse the meta-data date and time from [%s]"
" - cannot set the 'If-Modified-Since' header", " - cannot set the 'If-Modified-Since' header",
metaDataPath.Path()); metaDataPath.Path());
@@ -131,6 +125,20 @@ AbstractServerProcess::IfModifiedSinceHeaderValue(BString& headerValue,
} }
/*static*/ void
AbstractServerProcess::SetIfModifiedSinceHeaderValueFromMetaData(
BString& headerValue,
const StandardMetaData& metaData)
{
// An example of this output would be; 'Fri, 24 Oct 2014 19:32:27 +0000'
BDateTime modifiedDateTime = metaData
.GetDataModifiedTimestampAsDateTime();
BPrivate::BHttpTime modifiedHttpTime(modifiedDateTime);
headerValue.SetTo(modifiedHttpTime
.ToString(BPrivate::B_HTTP_TIME_FORMAT_COOKIE));
}
status_t status_t
AbstractServerProcess::PopulateMetaData( AbstractServerProcess::PopulateMetaData(
StandardMetaData& metaData, const BPath& path, StandardMetaData& metaData, const BPath& path,
@@ -158,7 +166,7 @@ AbstractServerProcess::PopulateMetaData(
/* static */ bool /* static */ bool
AbstractServerProcess::LooksLikeGzip(const char *pathStr) AbstractServerProcess::_LooksLikeGzip(const char *pathStr)
{ {
int l = strlen(pathStr); int l = strlen(pathStr);
return l > 4 && 0 == strncmp(&pathStr[l - 3], ".gz", 3); return l > 4 && 0 == strncmp(&pathStr[l - 3], ".gz", 3);
@@ -190,7 +198,7 @@ AbstractServerProcess::ParseJsonFromFileWithListener(
// compressed and the algorithm needs to decompress the data as // compressed and the algorithm needs to decompress the data as
// it is parsed. // it is parsed.
if (LooksLikeGzip(pathStr)) { if (_LooksLikeGzip(pathStr)) {
BDataIO* gzDecompressedInput = NULL; BDataIO* gzDecompressedInput = NULL;
BZlibDecompressionParameters* zlibDecompressionParameters BZlibDecompressionParameters* zlibDecompressionParameters
= new BZlibDecompressionParameters(); = new BZlibDecompressionParameters();
@@ -226,10 +234,18 @@ AbstractServerProcess::DownloadToLocalFileAtomically(
status_t result = DownloadToLocalFile( status_t result = DownloadToLocalFile(
temporaryFilePath, url, 0, 0); temporaryFilePath, url, 0, 0);
// if the data is coming in as .gz, but is not stored as .gz then
// the data should be decompressed in the temporary file location
// before being shifted into place.
if (result == B_OK
&& _LooksLikeGzip(url.Path())
&& !_LooksLikeGzip(targetFilePath.Path()))
result = _DeGzipInSitu(temporaryFilePath);
// not copying if the data has not changed because the data will be // not copying if the data has not changed because the data will be
// zero length. This is if the result is APP_ERR_NOT_MODIFIED. // zero length. This is if the result is APP_ERR_NOT_MODIFIED.
if (result == B_OK) { if (result == B_OK) {
// if the file is zero length then assume that something has // if the file is zero length then assume that something has
// gone wrong. // gone wrong.
off_t size; off_t size;
@@ -251,6 +267,45 @@ AbstractServerProcess::DownloadToLocalFileAtomically(
} }
/*static*/ status_t
AbstractServerProcess::_DeGzipInSitu(const BPath& path)
{
const char* tmpPath = tmpnam(NULL);
status_t result = B_OK;
{
BFile file(path.Path(), O_RDONLY);
BFile tmpFile(tmpPath, O_WRONLY | O_CREAT);
BDataIO* gzDecompressedInput = NULL;
BZlibDecompressionParameters* zlibDecompressionParameters
= new BZlibDecompressionParameters();
result = BZlibCompressionAlgorithm()
.CreateDecompressingInputStream(&file,
zlibDecompressionParameters, gzDecompressedInput);
if (result == B_OK) {
ObjectDeleter<BDataIO> gzDecompressedInputDeleter(
gzDecompressedInput);
result = DataIOUtils::CopyAll(&tmpFile, gzDecompressedInput);
}
}
if (result == B_OK) {
if (rename(tmpPath, path.Path()) != 0) {
HDERROR("unable to move the uncompressed data into place");
result = B_ERROR;
}
}
else {
HDERROR("it was not possible to decompress the data");
}
return result;
}
status_t status_t
AbstractServerProcess::DownloadToLocalFile(const BPath& targetFilePath, AbstractServerProcess::DownloadToLocalFile(const BPath& targetFilePath,
const BUrl& url, uint32 redirects, uint32 failures) const BUrl& url, uint32 redirects, uint32 failures)
@@ -1,9 +1,7 @@
/* /*
* Copyright 2017-2018, Andrew Lindesay <[email protected]>. * Copyright 2017-2020, Andrew Lindesay <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
#ifndef ABSTRACT_SERVER_PROCESS_H #ifndef ABSTRACT_SERVER_PROCESS_H
#define ABSTRACT_SERVER_PROCESS_H #define ABSTRACT_SERVER_PROCESS_H
@@ -39,12 +37,15 @@ protected:
virtual void GetStandardMetaDataJsonPath( virtual void GetStandardMetaDataJsonPath(
BString& jsonPath) const = 0; BString& jsonPath) const = 0;
status_t IfModifiedSinceHeaderValue( virtual status_t IfModifiedSinceHeaderValue(
BString& headerValue) const; BString& headerValue) const;
status_t IfModifiedSinceHeaderValue( status_t IfModifiedSinceHeaderValue(
BString& headerValue, BString& headerValue,
const BPath& metaDataPath, const BPath& metaDataPath,
const BString& jsonPath) const; const BString& jsonPath) const;
static void SetIfModifiedSinceHeaderValueFromMetaData(
BString& headerValue,
const StandardMetaData& metaData);
status_t PopulateMetaData( status_t PopulateMetaData(
StandardMetaData& metaData, StandardMetaData& metaData,
@@ -55,7 +56,7 @@ protected:
BJsonEventListener *listener, BJsonEventListener *listener,
const BPath& path) const; const BPath& path) const;
status_t DownloadToLocalFileAtomically( virtual status_t DownloadToLocalFileAtomically(
const BPath& targetFilePath, const BPath& targetFilePath,
const BUrl& url); const BUrl& url);
@@ -72,17 +73,18 @@ protected:
virtual status_t StopInternal(); virtual status_t StopInternal();
private: private:
uint32 fOptions;
BHttpRequest* fRequest;
status_t DownloadToLocalFile( status_t DownloadToLocalFile(
const BPath& targetFilePath, const BPath& targetFilePath,
const BUrl& url, const BUrl& url,
uint32 redirects, uint32 failures); uint32 redirects, uint32 failures);
static bool LooksLikeGzip(const char *pathStr); static bool _LooksLikeGzip(const char *pathStr);
static status_t _DeGzipInSitu(const BPath& path);
private:
uint32 fOptions;
BHttpRequest* fRequest;
}; };
#endif // ABSTRACT_SERVER_PROCESS_H #endif // ABSTRACT_SERVER_PROCESS_H
@@ -2,55 +2,106 @@
* Copyright 2017-2020, Andrew Lindesay <[email protected]>. * Copyright 2017-2020, Andrew Lindesay <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
#include "ServerIconExportUpdateProcess.h" #include "ServerIconExportUpdateProcess.h"
#include <sys/stat.h> #include <sys/stat.h>
#include <time.h> #include <time.h>
#include <AutoDeleter.h>
#include <AutoLocker.h> #include <AutoLocker.h>
#include <Catalog.h> #include <Catalog.h>
#include <FileIO.h> #include <FileIO.h>
#include <support/StopWatch.h>
#include <support/ZlibCompressionAlgorithm.h>
#include "DataIOUtils.h"
#include "HaikuDepotConstants.h" #include "HaikuDepotConstants.h"
#include "Logger.h" #include "Logger.h"
#include "ServerHelper.h" #include "ServerHelper.h"
#include "ServerSettings.h" #include "StandardMetaDataJsonEventListener.h"
#include "StorageUtils.h" #include "StorageUtils.h"
#include "TarArchiveService.h" #include "TarArchiveService.h"
#define ENTRY_PATH_METADATA "hicn/info.json"
#undef B_TRANSLATION_CONTEXT #undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "ServerIconExportUpdateProcess" #define B_TRANSLATION_CONTEXT "ServerIconExportUpdateProcess"
/*! This constructor will locate the cached data in a standardized location */ /*! This listener will scan the files that are available in the tar file and
find the meta-data file. This is a JSON piece of data that describes the
timestamp of the last modified data in the tar file. This is then used to
establish if the server has any newer data and hence if it is worth
downloading fresh data. The process uses the standard HTTP
If-Modified-Since header.
*/
class InfoJsonExtractEntryListener : public TarEntryListener
{
public:
InfoJsonExtractEntryListener();
virtual ~InfoJsonExtractEntryListener();
virtual status_t Handle(
const TarArchiveHeader& header,
size_t offset,
BDataIO *data);
BPositionIO& GetInfoJsonData();
private:
BMallocIO fInfoJsonData;
};
InfoJsonExtractEntryListener::InfoJsonExtractEntryListener()
{
}
InfoJsonExtractEntryListener::~InfoJsonExtractEntryListener()
{
}
BPositionIO&
InfoJsonExtractEntryListener::GetInfoJsonData()
{
return fInfoJsonData;
}
status_t
InfoJsonExtractEntryListener::Handle( const TarArchiveHeader& header,
size_t offset, BDataIO *data)
{
if (header.Length() > 0 && header.FileName() == ENTRY_PATH_METADATA) {
status_t copyResult = DataIOUtils::CopyAll(&fInfoJsonData, data);
if (copyResult == B_OK) {
HDINFO("[InfoJsonExtractEntryListener] did extract [%s]",
ENTRY_PATH_METADATA);
fInfoJsonData.Seek(0, SEEK_SET);
return B_CANCELED;
// this will prevent further scanning of the tar file
}
return copyResult;
}
return B_OK;
}
/*! This constructor will locate the cached data in a standardized location
*/
ServerIconExportUpdateProcess::ServerIconExportUpdateProcess( ServerIconExportUpdateProcess::ServerIconExportUpdateProcess(
Model* model, Model* model,
uint32 serverProcessOptions) uint32 serverProcessOptions)
: :
AbstractServerProcess(serverProcessOptions), AbstractSingleFileServerProcess(serverProcessOptions),
fModel(model), fModel(model)
fCountIconsSet(0)
{ {
AutoLocker<BLocker> locker(fModel->Lock());
if (fModel->IconStoragePath(fLocalIconStoragePath) != B_OK) {
HDINFO("[%s] unable to obtain the path for storing icons", Name());
fLocalIconStoragePath.Unset();
fLocalIconStore = NULL;
} else {
fLocalIconStore = new LocalIconStore(fLocalIconStoragePath);
}
} }
ServerIconExportUpdateProcess::~ServerIconExportUpdateProcess() ServerIconExportUpdateProcess::~ServerIconExportUpdateProcess()
{ {
delete fLocalIconStore;
} }
@@ -69,250 +120,100 @@ ServerIconExportUpdateProcess::Description() const
status_t status_t
ServerIconExportUpdateProcess::RunInternal() ServerIconExportUpdateProcess::ProcessLocalData()
{ {
status_t result = B_OK; status_t result = fModel->InitPackageIconRepository();
_NotifyPackagesWithIconsInDepots();
return result;
}
if (NULL == fLocalIconStore || fLocalIconStoragePath.Path() == NULL)
result = B_ERROR;
if (IsSuccess(result) && HasOption(SERVER_PROCESS_DROP_CACHE)) { status_t
result = StorageUtils::RemoveDirectoryContents(fLocalIconStoragePath); ServerIconExportUpdateProcess::GetLocalPath(BPath& path) const
} {
return fModel->IconTarPath(path);
}
/*! This overridden method implementation seems inefficient because it will
apparently scan the entire tarball for the file that it is looking for, but
actually it will cancel the scan once it has found it's target object (the
JSON data containing the meta-data) and by convention, the server side will
place the meta-data as one of the first objects in the tar-ball so it will
find it quickly.
*/
status_t
ServerIconExportUpdateProcess::IfModifiedSinceHeaderValue(BString& headerValue) const
{
headerValue.SetTo("");
BPath tarPath;
status_t result = GetLocalPath(tarPath);
// early exit if the tar file is not there.
if (result == B_OK) { if (result == B_OK) {
bool hasData; off_t size;
bool hasFile;
result = HasLocalData(&hasData); result = StorageUtils::ExistsObject(tarPath, &hasFile, NULL, &size);
if (result == B_OK && ShouldAttemptNetworkDownload(hasData)) if (result == B_OK && (!hasFile || size == 0))
result = _DownloadAndUnpack();
if (IsSuccess(result)) {
status_t hasDataResult = HasLocalData(&hasData);
if (hasDataResult == B_OK && !hasData)
result = HD_ERR_NO_DATA;
}
}
if (IsSuccess(result) && !WasStopped())
result = Populate();
return result;
}
status_t
ServerIconExportUpdateProcess::Populate()
{
BStopWatch watch("ServerIconExportUpdateProcess::Populate", true);
DepotList depots = fModel->Depots();
status_t result = B_OK;
{
AutoLocker<BLocker> locker(fModel->Lock());
depots = fModel->Depots();
}
HDDEBUG("[%s] will populate icons for %" B_PRId32 " depots", Name(),
depots.CountItems());
for (int32 i = 0;
(i < depots.CountItems()) && !WasStopped() && (result == B_OK);
i++) {
AutoLocker<BLocker> locker(fModel->Lock());
DepotInfo depotInfo = depots.ItemAtFast(i);
result = PopulateForDepot(depotInfo);
}
if (Logger::IsInfoEnabled()) {
double secs = watch.ElapsedTime() / 1000000.0;
HDINFO("[%s] did populate %" B_PRId32 " packages' icons (%6.3g secs)",
Name(), fCountIconsSet, secs);
}
return result;
}
/*! This method assumes that the model lock has been acquired */
status_t
ServerIconExportUpdateProcess::PopulateForDepot(const DepotInfo& depot)
{
HDINFO("[%s] will populate icons for depot [%s]",
Name(), depot.Name().String());
status_t result = B_OK;
const PackageList& packages = depot.Packages();
for(int32 j = 0;
(j < packages.CountItems()) && !WasStopped() && (result == B_OK);
j++) {
const PackageInfoRef& packageInfoRef = packages.ItemAtFast(j);
result = PopulateForPkg(packageInfoRef);
if (result == B_FILE_NOT_FOUND)
result = B_OK;
}
return result;
}
/*! This method assumes that the model lock has been acquired */
status_t
ServerIconExportUpdateProcess::PopulateForPkg(const PackageInfoRef& package)
{
BPath bestIconPath;
if ( fLocalIconStore->TryFindIconPath(
package->Name(), bestIconPath) == B_OK) {
BFile bestIconFile(bestIconPath.Path(), O_RDONLY);
BitmapRef bitmapRef(new(std::nothrow)SharedBitmap(bestIconFile), true);
package->SetIcon(bitmapRef);
HDDEBUG("[%s] have set the package icon for [%s] from [%s]",
Name(), package->Name().String(), bestIconPath.Path());
fCountIconsSet++;
return B_OK;
}
HDDEBUG("[%s] did not set the package icon for [%s]; no data",
Name(), package->Name().String());
return B_FILE_NOT_FOUND;
}
status_t
ServerIconExportUpdateProcess::_DownloadAndUnpack()
{
BPath tarGzFilePath(tmpnam(NULL));
status_t result = B_OK;
HDINFO("[%s] will start fetching icons", Name());
result = _Download(tarGzFilePath);
switch (result) {
case HD_ERR_NOT_MODIFIED:
HDINFO("[%s] icons not modified - will use existing", Name());
return result; return result;
case B_OK:
return _Unpack(tarGzFilePath);
default:
return (_HandleDownloadFailure() != B_OK) ? result : B_OK;
}
}
/*! if the download failed, but there are existing icons in place to use
then use those icons. To detect the existing files, look for the
icons' meta-info file.
*/
status_t
ServerIconExportUpdateProcess::_HandleDownloadFailure()
{
bool hasData;
status_t result = HasLocalData(&hasData);
if (result == B_OK) {
if (hasData) {
HDINFO("[%s] failed to update data, but have old data anyway "
"so will carry on with that", Name());
} else {
HDINFO("[%s] failed to obtain data", Name());
result = HD_ERR_NO_DATA;
}
} else {
HDERROR("[%s] unable to detect if there is local data\n", Name());
} }
return result;
}
/*! The tar-ball data of icons has arrived and so old data needs to be purged
to make way for the new data and the new data needs to be unpacked.
*/
status_t
ServerIconExportUpdateProcess::_Unpack(BPath& tarGzFilePath)
{
status_t result;
HDINFO("[%s] delete any existing stored data", Name());
StorageUtils::RemoveDirectoryContents(fLocalIconStoragePath);
BFile *tarGzFile = new BFile(tarGzFilePath.Path(), O_RDONLY);
BDataIO* tarIn;
BZlibDecompressionParameters* zlibDecompressionParameters
= new BZlibDecompressionParameters();
result = BZlibCompressionAlgorithm()
.CreateDecompressingInputStream(tarGzFile,
zlibDecompressionParameters, tarIn);
if (result == B_OK) { if (result == B_OK) {
BStopWatch watch( BFile *tarIo = new BFile(tarPath.Path(), O_RDONLY);
"ServerIconExportUpdateProcess::DownloadAndUnpack_Unpack", ObjectDeleter<BFile> tarIoDeleter(tarIo);
true); InfoJsonExtractEntryListener* extractDataListener
= new InfoJsonExtractEntryListener();
ObjectDeleter<InfoJsonExtractEntryListener> extractDataListenerDeleter(
extractDataListener);
result = TarArchiveService::ForEachEntry(*tarIo, extractDataListener);
result = TarArchiveService::Unpack(*tarIn, if (result == B_CANCELED) {
fLocalIconStoragePath, NULL); // the cancellation is expected because it will cancel when it finds
// the meta-data file to avoid any further cost of traversing the
// tar-ball.
result = B_OK;
if (result == B_OK) { StandardMetaData metaData;
double secs = watch.ElapsedTime() / 1000000.0; BString metaDataJsonPath;
HDINFO("[%s] did unpack icon tgz in (%6.3g secs)", Name(), secs); GetStandardMetaDataJsonPath(metaDataJsonPath);
StandardMetaDataJsonEventListener parseInfoJsonListener(
metaDataJsonPath, metaData);
BPrivate::BJson::Parse(
&(extractDataListener->GetInfoJsonData()),
&parseInfoJsonListener);
if (0 != remove(tarGzFilePath.Path())) { result = parseInfoJsonListener.ErrorStatus();
HDERROR("[%s] unable to delete the temporary tgz path; %s",
Name(), tarGzFilePath.Path()); // An example of this output would be; 'Fri, 24 Oct 2014 19:32:27 +0000'
if (result == B_OK) {
SetIfModifiedSinceHeaderValueFromMetaData(
headerValue, metaData);
} else {
HDERROR("[%s] unable to parse the meta data from the tar file",
Name());
} }
} else {
HDERROR("[%s] did not find the metadata [%s] in the tar",
Name(), ENTRY_PATH_METADATA);
result = B_BAD_DATA;
} }
} }
delete tarGzFile;
HDINFO("[%s] did complete unpacking icons", Name());
return result; return result;
} }
status_t
ServerIconExportUpdateProcess::HasLocalData(bool* result) const
{
BPath path;
status_t status = GetStandardMetaDataPath(path);
if (status != B_OK)
return status;
off_t size;
status = StorageUtils::ExistsObject(path, result, NULL, &size);
if (status == B_OK && size == 0)
*result = false;
return status;
}
status_t status_t
ServerIconExportUpdateProcess::GetStandardMetaDataPath(BPath& path) const ServerIconExportUpdateProcess::GetStandardMetaDataPath(BPath& path) const
{ {
status_t result = fModel->IconStoragePath(path); return B_ERROR;
// unsupported
if (result != B_OK)
return result;
path.Append("hicn/info.json");
return B_OK;
} }
@@ -320,17 +221,40 @@ void
ServerIconExportUpdateProcess::GetStandardMetaDataJsonPath( ServerIconExportUpdateProcess::GetStandardMetaDataJsonPath(
BString& jsonPath) const BString& jsonPath) const
{ {
// the "$" here indicates that the data is at the top level.
jsonPath.SetTo("$"); jsonPath.SetTo("$");
// the "$" here indicates that the data is at the top level.
} }
status_t BString
ServerIconExportUpdateProcess::_Download(BPath& tarGzFilePath) ServerIconExportUpdateProcess::UrlPathComponent()
{ {
return DownloadToLocalFileAtomically(tarGzFilePath, return "/__pkgicon/all.tar.gz";
ServerSettings::CreateFullUrl("/__pkgicon/all.tar.gz"));
} }
void
ServerIconExportUpdateProcess::_NotifyPackagesWithIconsInDepots() const
{
const DepotList& depots = fModel->Depots();
for (int32 d = 0; d < depots.CountItems(); d++) {
const DepotInfo& depot = depots.ItemAtFast(d);
_NotifyPackagesWithIconsInDepot(depot);
}
}
void
ServerIconExportUpdateProcess::_NotifyPackagesWithIconsInDepot(
const DepotInfo& depot) const
{
PackageIconRepository& packageIconRepository
= fModel->GetPackageIconRepository();
const PackageList& packages = depot.Packages();
for (int32 p = 0; p < packages.CountItems(); p++) {
AutoLocker<BLocker> locker(fModel->Lock());
const PackageInfoRef& packageInfoRef = packages.ItemAtFast(p);
if (packageIconRepository.HasAnyIcon(packageInfoRef->Name()))
packages.ItemAtFast(p)->NotifyChangedIcon();
}
}
@@ -1,5 +1,5 @@
/* /*
* Copyright 2017-2018, Andrew Lindesay <[email protected]>. * Copyright 2017-2020, Andrew Lindesay <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
#ifndef SERVER_ICON_EXPORT_UPDATE_PROCESS_H #ifndef SERVER_ICON_EXPORT_UPDATE_PROCESS_H
@@ -11,15 +11,14 @@
#include <String.h> #include <String.h>
#include <Url.h> #include <Url.h>
#include "AbstractServerProcess.h" #include "AbstractSingleFileServerProcess.h"
#include "LocalIconStore.h"
#include "Model.h" #include "Model.h"
class DumpExportPkg; class DumpExportPkg;
class ServerIconExportUpdateProcess : public AbstractServerProcess { class ServerIconExportUpdateProcess : public AbstractSingleFileServerProcess {
public: public:
ServerIconExportUpdateProcess( ServerIconExportUpdateProcess(
@@ -29,26 +28,27 @@ public:
const char* Name() const; const char* Name() const;
const char* Description() const; const char* Description() const;
status_t RunInternal(); virtual status_t ProcessLocalData();
virtual status_t GetLocalPath(BPath& path) const;
virtual status_t IfModifiedSinceHeaderValue(
BString& headerValue) const;
virtual status_t GetStandardMetaDataPath(BPath& path) const;
virtual void GetStandardMetaDataJsonPath(
BString& jsonPath) const;
protected: protected:
status_t PopulateForPkg(const PackageInfoRef& package); virtual BString UrlPathComponent();
status_t PopulateForDepot(const DepotInfo& depot);
status_t Populate();
status_t HasLocalData(bool* result) const;
status_t GetStandardMetaDataPath(BPath& path) const;
void GetStandardMetaDataJsonPath(
BString& jsonPath) const;
private:
status_t _Unpack(BPath& tarGzFilePath);
status_t _HandleDownloadFailure();
status_t _DownloadAndUnpack();
status_t _Download(BPath& tarGzFilePath);
private:
void _NotifyPackagesWithIconsInDepots() const;
void _NotifyPackagesWithIconsInDepot(
const DepotInfo& depotInfo) const;
private:
Model* fModel; Model* fModel;
BPath fLocalIconStoragePath;
LocalIconStore* fLocalIconStore;
int32 fCountIconsSet;
}; };
@@ -1,5 +1,5 @@
/* /*
* Copyright 2017, Andrew Lindesay <[email protected]>. * Copyright 2017-2020, Andrew Lindesay <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
@@ -14,7 +14,7 @@ StandardMetaData::StandardMetaData()
} }
BDateTime /*static*/ BDateTime
StandardMetaData::_CreateDateTime(uint64_t millisSinceEpoc) StandardMetaData::_CreateDateTime(uint64_t millisSinceEpoc)
{ {
time_t secondsSinceEpoc = (millisSinceEpoc / 1000); time_t secondsSinceEpoc = (millisSinceEpoc / 1000);
@@ -25,14 +25,14 @@ StandardMetaData::_CreateDateTime(uint64_t millisSinceEpoc)
uint64_t uint64_t
StandardMetaData::GetCreateTimestamp() StandardMetaData::GetCreateTimestamp() const
{ {
return fCreateTimestamp; return fCreateTimestamp;
} }
BDateTime BDateTime
StandardMetaData::GetCreateTimestampAsDateTime() StandardMetaData::GetCreateTimestampAsDateTime() const
{ {
return _CreateDateTime(GetCreateTimestamp()); return _CreateDateTime(GetCreateTimestamp());
} }
@@ -46,7 +46,7 @@ StandardMetaData::SetCreateTimestamp(uint64_t value)
uint64_t uint64_t
StandardMetaData::GetDataModifiedTimestamp() StandardMetaData::GetDataModifiedTimestamp() const
{ {
return fDataModifiedTimestamp; return fDataModifiedTimestamp;
} }
@@ -60,14 +60,14 @@ StandardMetaData::SetDataModifiedTimestamp(uint64_t value)
BDateTime BDateTime
StandardMetaData::GetDataModifiedTimestampAsDateTime() StandardMetaData::GetDataModifiedTimestampAsDateTime() const
{ {
return _CreateDateTime(GetDataModifiedTimestamp()); return _CreateDateTime(GetDataModifiedTimestamp());
} }
bool bool
StandardMetaData::IsPopulated() StandardMetaData::IsPopulated() const
{ {
return fCreateTimestamp != 0 && fDataModifiedTimestamp != 0; return fCreateTimestamp != 0 && fDataModifiedTimestamp != 0;
} }
+10 -7
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2017, Andrew Lindesay <[email protected]>. * Copyright 2017-2020, Andrew Lindesay <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
#ifndef STANDARD_META_DATA_H #ifndef STANDARD_META_DATA_H
@@ -23,19 +23,22 @@ class StandardMetaData {
public: public:
StandardMetaData(); StandardMetaData();
uint64_t GetCreateTimestamp(); uint64_t GetCreateTimestamp() const;
BDateTime GetCreateTimestampAsDateTime(); BDateTime GetCreateTimestampAsDateTime() const;
void SetCreateTimestamp(uint64_t value); void SetCreateTimestamp(uint64_t value);
uint64_t GetDataModifiedTimestamp(); uint64_t GetDataModifiedTimestamp() const;
BDateTime GetDataModifiedTimestampAsDateTime(); BDateTime GetDataModifiedTimestampAsDateTime()
const;
void SetDataModifiedTimestamp( void SetDataModifiedTimestamp(
uint64_t value); uint64_t value);
bool IsPopulated(); bool IsPopulated() const;
private: private:
BDateTime _CreateDateTime( static BDateTime _CreateDateTime(
uint64_t millisSinceEpoc); uint64_t millisSinceEpoc);
private:
uint64_t fCreateTimestamp; uint64_t fCreateTimestamp;
uint64_t fDataModifiedTimestamp; uint64_t fDataModifiedTimestamp;
}; };
+30 -117
View File
@@ -5,144 +5,57 @@
#include "TarArchiveHeader.h" #include "TarArchiveHeader.h"
#include "Logger.h"
#define OFFSET_FILENAME 0 TarArchiveHeader::TarArchiveHeader()
#define OFFSET_LENGTH 124 :
#define OFFSET_CHECKSUM 148 fFileName(),
#define OFFSET_FILETYPE 156 fLength(0),
fFileType(TAR_FILE_TYPE_NORMAL)
#define LENGTH_FILENAME 100
#define LENGTH_LENGTH 12
#define LENGTH_CHECKSUM 8
#define LENGTH_BLOCK 512
TarArchiveHeader::TarArchiveHeader(const BString& fileName, uint64 length,
tar_file_type fileType)
:
fFileName(fileName),
fLength(length),
fFileType(fileType)
{ {
} }
tar_file_type
TarArchiveHeader::_ReadFileType(unsigned char data) {
switch (data) {
case 0:
case '0':
return TAR_FILE_TYPE_NORMAL;
default: TarArchiveHeader::~TarArchiveHeader()
return TAR_FILE_TYPE_OTHER;
}
}
const BString
TarArchiveHeader::_ReadString(const unsigned char *data, size_t dataLength)
{ {
uint32 actualLength = 0;
while (actualLength < dataLength && 0 != data[actualLength])
actualLength++;
return BString((const char *) data, actualLength);
} }
/*
* This is an octal value represented as an ASCII string.
*/
static bool tar_is_octal_digit(unsigned char c)
{
switch (c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
return true;
default:
return false;
}
}
uint32
TarArchiveHeader::_ReadNumeric(const unsigned char *data, size_t dataLength)
{
uint32 actualLength = 0;
while (actualLength < dataLength && tar_is_octal_digit(data[actualLength]))
actualLength++;
uint32 factor = 1;
uint32 result = 0;
for (uint32 i = 0; i < actualLength; i++) {
result += (data[actualLength - (1 + i)] - '0') * factor;
factor *= 8;
}
return result;
}
uint32
TarArchiveHeader::_CalculateChecksum(const unsigned char* block)
{
uint32 result = 0;
for (uint32 i = 0; i < LENGTH_BLOCK; i++) {
if (i >= OFFSET_CHECKSUM && i < OFFSET_CHECKSUM + LENGTH_CHECKSUM)
result += 32;
else
result += block[i];
}
return result;
}
TarArchiveHeader*
TarArchiveHeader::CreateFromBlock(const unsigned char* block)
{
uint32 actualChecksum = _CalculateChecksum(block);
uint32 expectedChecksum = _ReadNumeric(&block[OFFSET_CHECKSUM],
LENGTH_CHECKSUM);
if(actualChecksum != expectedChecksum) {
HDERROR("tar archive header has bad checksum;"
"expected %" B_PRIu32 " actual %" B_PRIu32,
expectedChecksum, actualChecksum);
} else {
return new TarArchiveHeader(
_ReadString(&block[OFFSET_FILENAME], LENGTH_FILENAME),
_ReadNumeric(&block[OFFSET_LENGTH], LENGTH_LENGTH),
_ReadFileType(block[OFFSET_FILETYPE]));
}
return NULL;
}
const BString& const BString&
TarArchiveHeader::GetFileName() const TarArchiveHeader::FileName() const
{ {
return fFileName; return fFileName;
} }
size_t size_t
TarArchiveHeader::GetLength() const TarArchiveHeader::Length() const
{ {
return fLength; return fLength;
} }
tar_file_type tar_file_type
TarArchiveHeader::GetFileType() const TarArchiveHeader::FileType() const
{ {
return fFileType; return fFileType;
} }
void
TarArchiveHeader::SetFileName(const BString& value)
{
fFileName = value;
}
void
TarArchiveHeader::SetLength(size_t value)
{
fLength = value;
}
void
TarArchiveHeader::SetFileType(tar_file_type value)
{
fFileType = value;
}
+10 -19
View File
@@ -1,8 +1,7 @@
/* /*
* Copyright 2017, Andrew Lindesay <[email protected]>. * Copyright 2017-2020, Andrew Lindesay <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
#ifndef TAR_ARCHIVE_HEADER_H #ifndef TAR_ARCHIVE_HEADER_H
#define TAR_ARCHIVE_HEADER_H #define TAR_ARCHIVE_HEADER_H
@@ -21,28 +20,20 @@ enum tar_file_type {
class TarArchiveHeader { class TarArchiveHeader {
public: public:
TarArchiveHeader(const BString& fileName, TarArchiveHeader();
uint64 length, tar_file_type fileType); virtual ~TarArchiveHeader();
static TarArchiveHeader* CreateFromBlock(const unsigned char *block); const BString& FileName() const;
size_t Length() const;
const BString& GetFileName() const; tar_file_type FileType() const;
size_t GetLength() const;
tar_file_type GetFileType() const;
void SetFileName(const BString& value);
void SetLength(size_t value);
void SetFileType(tar_file_type value);
private: private:
static uint32 _CalculateChecksum( BString fFileName;
const unsigned char* data);
static const BString _ReadString(const unsigned char* data,
size_t dataLength);
static uint32 _ReadNumeric(const unsigned char* data,
size_t dataLength);
static tar_file_type _ReadFileType(unsigned char data);
const BString fFileName;
uint64 fLength; uint64 fLength;
tar_file_type fFileType; tar_file_type fFileType;
}; };
#endif // TAR_ARCHIVE_HEADER_H #endif // TAR_ARCHIVE_HEADER_H
+163 -132
View File
@@ -2,186 +2,217 @@
* Copyright 2017-2020, Andrew Lindesay <[email protected]>. * Copyright 2017-2020, Andrew Lindesay <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
#include "TarArchiveService.h" #include "TarArchiveService.h"
#include <AutoDeleter.h>
#include <Directory.h> #include <Directory.h>
#include <File.h> #include <File.h>
#include <StringList.h> #include <StringList.h>
#include "DataIOUtils.h"
#include "Logger.h" #include "Logger.h"
#include "StorageUtils.h" #include "StorageUtils.h"
#define OFFSET_FILENAME 0
#define OFFSET_LENGTH 124
#define OFFSET_CHECKSUM 148
#define OFFSET_FILETYPE 156
#define LENGTH_FILENAME 100
#define LENGTH_LENGTH 12
#define LENGTH_CHECKSUM 8
#define LENGTH_BLOCK 512 #define LENGTH_BLOCK 512
status_t /*! This method will parse the header that is located at the current position of
TarArchiveService::Unpack(BDataIO& tarDataIo, BPath& targetDirectory, the supplied tarIo. Upon success, the tarIo will point to the start of the
Stoppable* stoppable) data for the parsed entry.
*/
/*static*/ status_t
TarArchiveService::GetEntry(BPositionIO& tarIo, TarArchiveHeader& header)
{
uint8 buffer[LENGTH_BLOCK];
status_t result = tarIo.ReadExactly(buffer, LENGTH_BLOCK);
if (result == B_OK)
result = _ReadHeader(buffer, header);
return result;
}
/*! For each entry in the tar file, this method will call the listener. If the
listener does not return B_OK then the process will stop. This method is
useful for obtaining a catalog of items in the tar file for example.
*/
/*status*/ status_t
TarArchiveService::ForEachEntry(BPositionIO& tarIo, TarEntryListener* listener)
{ {
uint8 buffer[LENGTH_BLOCK]; uint8 buffer[LENGTH_BLOCK];
uint8 zero_buffer[LENGTH_BLOCK]; uint8 zero_buffer[LENGTH_BLOCK];
status_t result = B_OK; status_t result = B_OK;
uint32_t count_items_read = 0; uint32_t countItemsRead = 0;
off_t offset = 0;
HDINFO("will unpack to [%s]", targetDirectory.Path());
memset(zero_buffer, 0, sizeof zero_buffer); memset(zero_buffer, 0, sizeof zero_buffer);
tarIo.Seek(offset, SEEK_SET);
while (B_OK == result while (result == B_OK
&& (NULL == stoppable || !stoppable->WasStopped()) && B_OK == (result = tarIo.ReadExactly(
&& B_OK == (result = tarDataIo.ReadExactly(buffer, LENGTH_BLOCK))) { buffer, LENGTH_BLOCK))) {
count_items_read++; if (memcmp(zero_buffer, buffer, sizeof zero_buffer) == 0) {
HDDEBUG("detected end of tar-ball after %" B_PRIu32 " items",
if (0 == memcmp(zero_buffer, buffer, sizeof zero_buffer)) { countItemsRead);
HDDEBUG("detected end of tar-ball");
return B_OK; // end of tar-ball. return B_OK; // end of tar-ball.
} else {
TarArchiveHeader* header = TarArchiveHeader::CreateFromBlock(
buffer);
if (NULL == header) {
HDERROR("unable to parse a tar header");
result = B_ERROR;
}
if (B_OK == result)
result = _UnpackItem(tarDataIo, targetDirectory, *header);
delete header;
} }
}
HDERROR("did unpack %d tar items", count_items_read); TarArchiveHeader header;
result = _ReadHeader(buffer, header);
if (B_OK != result) { HDTRACE("did read tar entry header for [%s]",
HDERROR("error occurred unpacking tar items; %s", strerror(result)); header.FileName().String());
}
return result;
}
status_t
TarArchiveService::_EnsurePathToTarItemFile(
BPath& targetDirectoryPath, BString &tarItemPath)
{
if (tarItemPath.Length() == 0)
return B_ERROR;
BStringList components;
tarItemPath.Split("/", false, components);
for (int32 i = 0; i < components.CountStrings(); i++) {
BString component = components.StringAt(i);
if (_ValidatePathComponent(component) != B_OK) {
HDERROR("malformed component; [%s]", component.String());
return B_ERROR;
}
}
BPath parentPath;
BPath assembledPath(targetDirectoryPath);
status_t result = assembledPath.Append(tarItemPath);
if (result == B_OK)
result = assembledPath.GetParent(&parentPath);
if (result == B_OK)
result = create_directory(parentPath.Path(), 0777);
return result;
}
status_t
TarArchiveService::_UnpackItem(BDataIO& tarDataIo,
BPath& targetDirectoryPath,
TarArchiveHeader& header)
{
status_t result = B_OK;
BString entryFileName = header.GetFileName();
uint32 entryLength = header.GetLength();
HDDEBUG("will unpack item [%s] length [%" B_PRIu32 "]b",
entryFileName.String(), entryLength);
// if the path ends in "/" then it is a directory and there's no need to
// unpack it although if there is a length, it will need to be skipped.
if (!entryFileName.EndsWith("/") ||
header.GetFileType() != TAR_FILE_TYPE_NORMAL) {
result = _EnsurePathToTarItemFile(targetDirectoryPath,
entryFileName);
if (result == B_OK) { if (result == B_OK) {
BPath targetFilePath(targetDirectoryPath); countItemsRead++;
targetFilePath.Append(entryFileName, false);
result = _UnpackItemData(tarDataIo, targetFilePath, entryLength); // call out to the listener to read the data from the entry
// and/or just process the header information.
if (listener != NULL) {
BDataIO *entryData = new ConstraintedDataIO(&tarIo,
header.Length());
ObjectDeleter<BDataIO> entryDataDeleter(entryData);
result = listener->Handle(header, offset, entryData);
}
} }
} else {
off_t blocksToSkip = (entryLength / LENGTH_BLOCK);
if (entryLength % LENGTH_BLOCK > 0) offset += LENGTH_BLOCK;
blocksToSkip += 1; offset += _BytesRoundedToBlocks(header.Length());
if (0 != blocksToSkip) { if (result == B_OK)
uint8 buffer[LENGTH_BLOCK]; tarIo.Seek(offset, SEEK_SET);
}
for (uint32 i = 0; B_OK == result && i < blocksToSkip; i++) if (result == B_OK || result == B_CANCELED)
tarDataIo.ReadExactly(buffer, LENGTH_BLOCK); HDINFO("did list %" B_PRIu32 " tar items", countItemsRead);
} else
HDERROR("error occurred listing tar items; %s", strerror(result));
return result;
}
tar_file_type
TarArchiveService::_ReadHeaderFileType(unsigned char data) {
switch (data) {
case 0:
case '0':
return TAR_FILE_TYPE_NORMAL;
default:
return TAR_FILE_TYPE_OTHER;
}
}
/*const*/ const BString
TarArchiveService::_ReadHeaderString(const uint8 *data, size_t dataLength)
{
uint32 actualLength = 0;
while (actualLength < dataLength && 0 != data[actualLength])
actualLength++;
return BString((const char *) data, actualLength);
}
/*! This function will return true if the character supplied is a valid
character in an number expressed in octal.
*/
static bool tar_is_octal_digit(unsigned char c)
{
switch (c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
return true;
default:
return false;
}
}
/*static*/ uint32
TarArchiveService::_ReadHeaderNumeric(const uint8 *data, size_t dataLength)
{
uint32 actualLength = 0;
while (actualLength < dataLength && tar_is_octal_digit(data[actualLength]))
actualLength++;
uint32 factor = 1;
uint32 result = 0;
for (uint32 i = 0; i < actualLength; i++) {
result += (data[actualLength - (1 + i)] - '0') * factor;
factor *= 8;
} }
return result; return result;
} }
status_t /*static*/ uint32
TarArchiveService::_UnpackItemData(BDataIO& tarDataIo, TarArchiveService::_CalculateBlockChecksum(const uint8* block)
BPath& targetFilePath, uint32 length)
{ {
uint8 buffer[LENGTH_BLOCK]; uint32 result = 0;
size_t remainingInItem = length;
status_t result = B_OK;
BFile targetFile(targetFilePath.Path(), O_WRONLY | O_CREAT);
while (remainingInItem > 0 && for (uint32 i = 0; i < LENGTH_BLOCK; i++) {
B_OK == result && if (i >= OFFSET_CHECKSUM && i < OFFSET_CHECKSUM + LENGTH_CHECKSUM)
B_OK == (result = tarDataIo.ReadExactly(buffer, LENGTH_BLOCK))) { result += 32;
else
size_t writeFromBuffer = LENGTH_BLOCK; result += (uint32) block[i];
if (remainingInItem < LENGTH_BLOCK)
writeFromBuffer = remainingInItem;
result = targetFile.WriteExactly(buffer, writeFromBuffer);
remainingInItem -= writeFromBuffer;
}
if (result != B_OK) {
HDERROR("unable to unpack item data to; [%s]", targetFilePath.Path());
} }
return result; return result;
} }
status_t /*static*/ status_t
TarArchiveService::_ValidatePathComponent(const BString& component) TarArchiveService::_ReadHeader(const uint8* block, TarArchiveHeader& header)
{ {
if (component.Length() == 0) uint32 actualChecksum = _CalculateBlockChecksum(block);
return B_ERROR; uint32 expectedChecksum = _ReadHeaderNumeric(&block[OFFSET_CHECKSUM],
LENGTH_CHECKSUM);
if (component == ".." || component == "." || component == "~") if(actualChecksum != expectedChecksum) {
return B_ERROR; HDERROR("tar archive header has bad checksum;"
"expected %" B_PRIu32 " actual %" B_PRIu32,
expectedChecksum, actualChecksum);
return B_BAD_DATA;
}
header.SetFileName(
_ReadHeaderString(&block[OFFSET_FILENAME], LENGTH_FILENAME));
header.SetLength(
_ReadHeaderNumeric(&block[OFFSET_LENGTH], LENGTH_LENGTH));
header.SetFileType(
_ReadHeaderFileType(block[OFFSET_FILETYPE]));
return B_OK; return B_OK;
} }
/*static*/ off_t
TarArchiveService::_BytesRoundedToBlocks(off_t value)
{
if (0 != value % LENGTH_BLOCK)
return ((value / LENGTH_BLOCK) + 1) * LENGTH_BLOCK;
return (value / LENGTH_BLOCK) * LENGTH_BLOCK;
}
+27 -14
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2017-2018, Andrew Lindesay <[email protected]>. * Copyright 2017-2020, Andrew Lindesay <[email protected]>.
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
#ifndef TAR_ARCHIVE_SERVICE_H #ifndef TAR_ARCHIVE_SERVICE_H
@@ -12,24 +12,37 @@
#include <Path.h> #include <Path.h>
class TarEntryListener {
public:
virtual status_t Handle(
const TarArchiveHeader& header,
size_t offset,
BDataIO* data) = 0;
};
class TarArchiveService { class TarArchiveService {
public: public:
static status_t Unpack(BDataIO& tarDataIo, static status_t ForEachEntry(BPositionIO& tarIo,
BPath& targetDirectoryPath, TarEntryListener* listener);
Stoppable* stoppable); static status_t GetEntry(BPositionIO& tarIo,
TarArchiveHeader& header);
private: private:
static status_t _EnsurePathToTarItemFile( static status_t _ValidatePathComponent(
BPath& targetDirectoryPath,
BString &tarItemPath);
static status_t _ValidatePathComponent(
const BString& component); const BString& component);
static status_t _UnpackItem(BDataIO& tarDataIo,
BPath& targetDirectory, static off_t _BytesRoundedToBlocks(off_t value);
TarArchiveHeader& header); static uint32 _CalculateBlockChecksum(
static status_t _UnpackItemData(BDataIO& tarDataIo, const unsigned char* data);
BPath& targetFilePath,
uint32 length); static status_t _ReadHeader(const uint8* data,
TarArchiveHeader& header);
static const BString _ReadHeaderString(const uint8* data,
size_t dataLength);
static uint32 _ReadHeaderNumeric(const uint8* data,
size_t dataLength);
static tar_file_type _ReadHeaderFileType(uint8 data);
}; };
+2 -1
View File
@@ -26,6 +26,7 @@
#include "FeaturedPackagesView.h" #include "FeaturedPackagesView.h"
#include "Logger.h" #include "Logger.h"
#include "MainWindow.h" #include "MainWindow.h"
#include "PackageIconTarRepository.h"
#include "ServerHelper.h" #include "ServerHelper.h"
#include "ServerSettings.h" #include "ServerSettings.h"
#include "ScreenshotWindow.h" #include "ScreenshotWindow.h"
@@ -54,7 +55,7 @@ App::~App()
// We cannot let global destructors cleanup static BitmapRef objects, // We cannot let global destructors cleanup static BitmapRef objects,
// since calling BBitmap destructors needs a valid BApplication still // since calling BBitmap destructors needs a valid BApplication still
// around. That's why we do it here. // around. That's why we do it here.
PackageInfo::CleanupDefaultIcon(); PackageIconTarRepository::CleanupDefaultIcon();
FeaturedPackagesView::CleanupIcons(); FeaturedPackagesView::CleanupIcons();
ScreenshotWindow::CleanupIcons(); ScreenshotWindow::CleanupIcons();
} }
+23 -18
View File
@@ -55,12 +55,13 @@ static BitmapRef sInstalledIcon(new(std::nothrow)
class StackedFeaturedPackagesView : public BView { class StackedFeaturedPackagesView : public BView {
public: public:
StackedFeaturedPackagesView() StackedFeaturedPackagesView(Model& model)
: :
BView("stacked featured packages view", B_WILL_DRAW | B_FRAME_EVENTS), BView("stacked featured packages view", B_WILL_DRAW | B_FRAME_EVENTS),
fModel(model),
fSelectedIndex(-1),
fPackageListener( fPackageListener(
new(std::nothrow) OnePackageMessagePackageListener(this)), new(std::nothrow) OnePackageMessagePackageListener(this))
fSelectedIndex(-1)
{ {
SetEventMask(B_POINTER_EVENTS); SetEventMask(B_POINTER_EVENTS);
Clear(); Clear();
@@ -376,17 +377,20 @@ public:
void _DrawPackageIcon(BRect updateRect, PackageInfoRef pkg, float y, void _DrawPackageIcon(BRect updateRect, PackageInfoRef pkg, float y,
bool selected) bool selected)
{ {
BitmapRef icon = pkg->Icon(); BitmapRef icon;
status_t iconResult = fModel.GetPackageIconRepository().GetIcon(
pkg->Name(), BITMAP_SIZE_64, icon);
if (icon.Get() != NULL) { if (iconResult == B_OK) {
float inset = (HEIGHT_PACKAGE - SIZE_ICON) / 2.0; if (icon.Get() != NULL) {
BRect sourceRect = BRect(0, 0, SIZE_ICON, SIZE_ICON); float inset = (HEIGHT_PACKAGE - SIZE_ICON) / 2.0;
BRect targetRect = BRect(inset, y + inset, SIZE_ICON + inset, BRect targetRect = BRect(inset, y + inset, SIZE_ICON + inset,
y + SIZE_ICON + inset); y + SIZE_ICON + inset);
const BBitmap* bitmap = icon->Bitmap(SharedBitmap::SIZE_64); const BBitmap* bitmap = icon->Bitmap(BITMAP_SIZE_64);
SetDrawingMode(B_OP_ALPHA); SetDrawingMode(B_OP_ALPHA);
DrawBitmap(bitmap, bitmap->Bounds(), targetRect, DrawBitmap(bitmap, bitmap->Bounds(), targetRect,
B_FILTER_BITMAP_BILINEAR); B_FILTER_BITMAP_BILINEAR);
}
} }
} }
@@ -415,7 +419,7 @@ public:
if (pkg->State() == ACTIVATED) { if (pkg->State() == ACTIVATED) {
const BBitmap* bitmap = sInstalledIcon->Bitmap( const BBitmap* bitmap = sInstalledIcon->Bitmap(
SharedBitmap::SIZE_16); BITMAP_SIZE_16);
float stringWidth = StringWidth(pkg->Title()); float stringWidth = StringWidth(pkg->Title());
float offsetX = pt.x + stringWidth + PADDING; float offsetX = pt.x + stringWidth + PADDING;
BRect targetRect(offsetX, pt.y - 16, offsetX + 16, pt.y); BRect targetRect(offsetX, pt.y - 16, offsetX + 16, pt.y);
@@ -599,10 +603,10 @@ public:
private: private:
Model& fModel;
std::vector<PackageInfoRef> std::vector<PackageInfoRef>
fPackages; fPackages;
int32 fSelectedIndex; int32 fSelectedIndex;
OnePackageMessagePackageListener* OnePackageMessagePackageListener*
fPackageListener; fPackageListener;
}; };
@@ -611,11 +615,12 @@ private:
// #pragma mark - FeaturedPackagesView // #pragma mark - FeaturedPackagesView
FeaturedPackagesView::FeaturedPackagesView() FeaturedPackagesView::FeaturedPackagesView(Model& model)
: :
BView(B_TRANSLATE("Featured packages"), 0) BView(B_TRANSLATE("Featured packages"), 0),
fModel(model)
{ {
fPackagesView = new StackedFeaturedPackagesView(); fPackagesView = new StackedFeaturedPackagesView(fModel);
fScrollView = new BScrollView("featured packages scroll view", fScrollView = new BScrollView("featured packages scroll view",
fPackagesView, 0, false, true, B_FANCY_BORDER); fPackagesView, 0, false, true, B_FANCY_BORDER);
@@ -9,6 +9,7 @@
#include <View.h> #include <View.h>
#include "Model.h"
#include "PackageInfo.h" #include "PackageInfo.h"
#include "PackageInfoListener.h" #include "PackageInfoListener.h"
@@ -18,7 +19,7 @@ class StackedFeaturedPackagesView;
class FeaturedPackagesView : public BView { class FeaturedPackagesView : public BView {
public: public:
FeaturedPackagesView(); FeaturedPackagesView(Model& model);
virtual ~FeaturedPackagesView(); virtual ~FeaturedPackagesView();
virtual void DoLayout(); virtual void DoLayout();
@@ -33,10 +34,10 @@ public:
static void CleanupIcons(); static void CleanupIcons();
private: private:
void _AdjustViews(); void _AdjustViews();
private: private:
Model& fModel;
BScrollView* fScrollView; BScrollView* fScrollView;
StackedFeaturedPackagesView* StackedFeaturedPackagesView*
fPackagesView; fPackagesView;
+4 -4
View File
@@ -153,9 +153,9 @@ MainWindow::MainWindow(const BMessage& settings)
menuBar->MaxSize().height)); menuBar->MaxSize().height));
fFilterView = new FilterView(); fFilterView = new FilterView();
fFeaturedPackagesView = new FeaturedPackagesView(); fFeaturedPackagesView = new FeaturedPackagesView(fModel);
fPackageListView = new PackageListView(fModel.Lock()); fPackageListView = new PackageListView(&fModel);
fPackageInfoView = new PackageInfoView(fModel.Lock(), this); fPackageInfoView = new PackageInfoView(&fModel, this);
fSplitView = new BSplitView(B_VERTICAL, 5.0f); fSplitView = new BSplitView(B_VERTICAL, 5.0f);
@@ -236,7 +236,7 @@ MainWindow::MainWindow(const BMessage& settings, const PackageInfoRef& package)
debugger("unable to create the process coordinator semaphore"); debugger("unable to create the process coordinator semaphore");
fFilterView = new FilterView(); fFilterView = new FilterView();
fPackageInfoView = new PackageInfoView(fModel.Lock(), this); fPackageInfoView = new PackageInfoView(&fModel, this);
fWorkStatusView = new WorkStatusView("work status"); fWorkStatusView = new WorkStatusView("work status");
BLayoutBuilder::Group<>(this, B_VERTICAL) BLayoutBuilder::Group<>(this, B_VERTICAL)
+19 -12
View File
@@ -266,9 +266,10 @@ private:
class TitleView : public BGroupView { class TitleView : public BGroupView {
public: public:
TitleView() TitleView(PackageIconRepository& packageIconRepository)
: :
BGroupView("title view", B_HORIZONTAL) BGroupView("title view", B_HORIZONTAL),
fPackageIconRepository(packageIconRepository)
{ {
fIconView = new BitmapView("package icon view"); fIconView = new BitmapView("package icon view");
fTitleView = new BStringView("package title view", ""); fTitleView = new BStringView("package title view", "");
@@ -393,8 +394,12 @@ public:
void SetPackage(const PackageInfo& package) void SetPackage(const PackageInfo& package)
{ {
if (package.Icon().Get() != NULL) BitmapRef bitmap;
fIconView->SetBitmap(package.Icon(), SharedBitmap::SIZE_32); status_t iconResult = fPackageIconRepository.GetIcon(
package.Name(), BITMAP_SIZE_64, bitmap);
if (iconResult == B_OK)
fIconView->SetBitmap(bitmap, BITMAP_SIZE_32);
else else
fIconView->UnsetBitmap(); fIconView->UnsetBitmap();
@@ -447,6 +452,8 @@ public:
} }
private: private:
PackageIconRepository& fPackageIconRepository;
BitmapView* fIconView; BitmapView* fIconView;
BStringView* fTitleView; BStringView* fTitleView;
@@ -811,9 +818,9 @@ public:
fDescriptionView->SetText(package.ShortDescription(), fDescriptionView->SetText(package.ShortDescription(),
package.FullDescription()); package.FullDescription());
fEmailIconView->SetBitmap(&fEmailIcon, SharedBitmap::SIZE_16); fEmailIconView->SetBitmap(&fEmailIcon, BITMAP_SIZE_16);
_SetContactInfo(fEmailLinkView, package.Publisher().Email()); _SetContactInfo(fEmailLinkView, package.Publisher().Email());
fWebsiteIconView->SetBitmap(&fWebsiteIcon, SharedBitmap::SIZE_16); fWebsiteIconView->SetBitmap(&fWebsiteIcon, BITMAP_SIZE_16);
_SetContactInfo(fWebsiteLinkView, package.Publisher().Website()); _SetContactInfo(fWebsiteLinkView, package.Publisher().Website());
bool hasScreenshot = false; bool hasScreenshot = false;
@@ -1281,11 +1288,11 @@ private:
// #pragma mark - PackageInfoView // #pragma mark - PackageInfoView
PackageInfoView::PackageInfoView(BLocker* modelLock, PackageInfoView::PackageInfoView(Model* model,
PackageActionHandler* handler) PackageActionHandler* handler)
: :
BView("package info view", 0), BView("package info view", 0),
fModelLock(modelLock), fModel(model),
fPackageListener(new(std::nothrow) OnePackageMessagePackageListener(this)) fPackageListener(new(std::nothrow) OnePackageMessagePackageListener(this))
{ {
fCardLayout = new BCardLayout(); fCardLayout = new BCardLayout();
@@ -1310,7 +1317,7 @@ PackageInfoView::PackageInfoView(BLocker* modelLock,
fCardLayout->SetVisibleItem((int32)0); fCardLayout->SetVisibleItem((int32)0);
fTitleView = new TitleView(); fTitleView = new TitleView(fModel->GetPackageIconRepository());
fPackageActionView = new PackageActionView(handler); fPackageActionView = new PackageActionView(handler);
fPackageActionView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED, fPackageActionView->SetExplicitMaxSize(BSize(B_SIZE_UNLIMITED,
B_SIZE_UNSET)); B_SIZE_UNSET));
@@ -1364,7 +1371,7 @@ PackageInfoView::MessageReceived(BMessage* message)
if (package->Name() != name) if (package->Name() != name)
break; break;
BAutolock _(fModelLock); BAutolock _(fModel->Lock());
if ((changes & PKG_CHANGED_SUMMARY) != 0 if ((changes & PKG_CHANGED_SUMMARY) != 0
|| (changes & PKG_CHANGED_DESCRIPTION) != 0 || (changes & PKG_CHANGED_DESCRIPTION) != 0
@@ -1396,7 +1403,7 @@ PackageInfoView::MessageReceived(BMessage* message)
void void
PackageInfoView::SetPackage(const PackageInfoRef& packageRef) PackageInfoView::SetPackage(const PackageInfoRef& packageRef)
{ {
BAutolock _(fModelLock); BAutolock _(fModel->Lock());
if (packageRef.Get() == NULL) { if (packageRef.Get() == NULL) {
Clear(); Clear();
@@ -1441,7 +1448,7 @@ PackageInfoView::SetPackage(const PackageInfoRef& packageRef)
void void
PackageInfoView::Clear() PackageInfoView::Clear()
{ {
BAutolock _(fModelLock); BAutolock _(fModel->Lock());
fTitleView->Clear(); fTitleView->Clear();
fPackageActionView->Clear(); fPackageActionView->Clear();
+4 -2
View File
@@ -1,5 +1,6 @@
/* /*
* Copyright 2013-2014, Stephan Aßmus <superstippi@gmx.de>. * Copyright 2013-2014, Stephan Aßmus <superstippi@gmx.de>.
* Copyright 2020, Andrew Lindesay <apl@lindesay.co.nz>
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
#ifndef PACKAGE_INFO_VIEW_H #ifndef PACKAGE_INFO_VIEW_H
@@ -7,6 +8,7 @@
#include <GroupView.h> #include <GroupView.h>
#include "Model.h"
#include "PackageInfo.h" #include "PackageInfo.h"
#include "PackageInfoListener.h" #include "PackageInfoListener.h"
@@ -27,7 +29,7 @@ enum {
class PackageInfoView : public BView { class PackageInfoView : public BView {
public: public:
PackageInfoView(BLocker* modelLock, PackageInfoView(Model* model,
PackageActionHandler* handler); PackageActionHandler* handler);
virtual ~PackageInfoView(); virtual ~PackageInfoView();
@@ -40,7 +42,7 @@ public:
void Clear(); void Clear();
private: private:
BLocker* fModelLock; Model* fModel;
BCardLayout* fCardLayout; BCardLayout* fCardLayout;
TitleView* fTitleView; TitleView* fTitleView;
+80 -83
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2018, Andrew Lindesay, <apl@lindesay.co.nz>. * Copyright 2018-2020, Andrew Lindesay, <apl@lindesay.co.nz>.
* Copyright 2017, Julian Harnath, <julian.harnath@rwth-aachen.de>. * Copyright 2017, Julian Harnath, <julian.harnath@rwth-aachen.de>.
* Copyright 2015, Axel Dörfler, <axeld@pinc-software.de>. * Copyright 2015, Axel Dörfler, <axeld@pinc-software.de>.
* Copyright 2013-2014, Stephan Aßmus <superstippi@gmx.de>. * Copyright 2013-2014, Stephan Aßmus <superstippi@gmx.de>.
@@ -63,24 +63,18 @@ package_state_to_string(PackageInfoRef ref)
} }
// A field type displaying both a bitmap and a string so that the class PackageIconAndTitleField : public BStringField {
// tree display looks nicer (both text and bitmap are indented)
class SharedBitmapStringField : public BStringField {
typedef BStringField Inherited; typedef BStringField Inherited;
public: public:
SharedBitmapStringField(SharedBitmap* bitmap, PackageIconAndTitleField(
SharedBitmap::Size size, const char* packageName,
const char* string); const char* string);
virtual ~SharedBitmapStringField(); virtual ~PackageIconAndTitleField();
void SetBitmap(SharedBitmap* bitmap,
SharedBitmap::Size size);
const BBitmap* Bitmap() const
{ return fBitmap; }
const BString PackageName() const
{ return fPackageName; }
private: private:
BitmapRef fReference; const BString fPackageName;
const BBitmap* fBitmap;
}; };
@@ -111,12 +105,12 @@ private:
// BColumn for PackageListView which knows how to render // BColumn for PackageListView which knows how to render
// a SharedBitmapStringField // a PackageIconAndTitleField
// TODO: Code-duplication with DriveSetup PartitionList.h
class PackageColumn : public BTitledColumn { class PackageColumn : public BTitledColumn {
typedef BTitledColumn Inherited; typedef BTitledColumn Inherited;
public: public:
PackageColumn(const char* title, PackageColumn(Model* model,
const char* title,
float width, float minWidth, float width, float minWidth,
float maxWidth, uint32 truncateMode, float maxWidth, uint32 truncateMode,
alignment align = B_ALIGN_LEFT); alignment align = B_ALIGN_LEFT);
@@ -132,6 +126,7 @@ public:
static void InitTextMargin(BView* parent); static void InitTextMargin(BView* parent);
private: private:
Model* fModel;
uint32 fTruncateMode; uint32 fTruncateMode;
static float sTextMargin; static float sTextMargin;
}; };
@@ -141,14 +136,15 @@ private:
class PackageRow : public BRow { class PackageRow : public BRow {
typedef BRow Inherited; typedef BRow Inherited;
public: public:
PackageRow(const PackageInfoRef& package, PackageRow(
const PackageInfoRef& package,
PackageListener* listener); PackageListener* listener);
virtual ~PackageRow(); virtual ~PackageRow();
const PackageInfoRef& Package() const const PackageInfoRef& Package() const
{ return fPackage; } { return fPackage; }
void UpdateTitle(); void UpdateIconAndTitle();
void UpdateSummary(); void UpdateSummary();
void UpdateState(); void UpdateState();
void UpdateRating(); void UpdateRating();
@@ -161,7 +157,8 @@ public:
private: private:
PackageInfoRef fPackage; PackageInfoRef fPackage;
PackageInfoListenerRef fPackageListener; PackageInfoListenerRef
fPackageListener;
PackageRow* fNextInHash; PackageRow* fNextInHash;
// link for BOpenHashTable // link for BOpenHashTable
@@ -208,28 +205,17 @@ private:
// #pragma mark - SharedBitmapStringField // #pragma mark - SharedBitmapStringField
SharedBitmapStringField::SharedBitmapStringField(SharedBitmap* bitmap, PackageIconAndTitleField::PackageIconAndTitleField(const char* packageName,
SharedBitmap::Size size, const char* string) const char* string)
: :
Inherited(string), Inherited(string),
fBitmap(NULL) fPackageName(packageName)
{
SetBitmap(bitmap, size);
}
SharedBitmapStringField::~SharedBitmapStringField()
{ {
} }
void PackageIconAndTitleField::~PackageIconAndTitleField()
SharedBitmapStringField::SetBitmap(SharedBitmap* bitmap,
SharedBitmap::Size size)
{ {
fReference = bitmap;
fBitmap = bitmap != NULL ? bitmap->Bitmap(size) : NULL;
// TODO: cause a redraw?
} }
@@ -312,10 +298,11 @@ SizeField::SetSize(double size)
float PackageColumn::sTextMargin = 0.0; float PackageColumn::sTextMargin = 0.0;
PackageColumn::PackageColumn(const char* title, float width, float minWidth, PackageColumn::PackageColumn(Model* model, const char* title, float width,
float maxWidth, uint32 truncateMode, alignment align) float minWidth, float maxWidth, uint32 truncateMode, alignment align)
: :
Inherited(title, width, minWidth, maxWidth, align), Inherited(title, width, minWidth, maxWidth, align),
fModel(model),
fTruncateMode(truncateMode) fTruncateMode(truncateMode)
{ {
SetWantsEvents(true); SetWantsEvents(true);
@@ -325,14 +312,12 @@ PackageColumn::PackageColumn(const char* title, float width, float minWidth,
void void
PackageColumn::DrawField(BField* field, BRect rect, BView* parent) PackageColumn::DrawField(BField* field, BRect rect, BView* parent)
{ {
SharedBitmapStringField* bitmapField PackageIconAndTitleField* packageIconAndTitleField
= dynamic_cast<SharedBitmapStringField*>(field); = dynamic_cast<PackageIconAndTitleField*>(field);
BStringField* stringField = dynamic_cast<BStringField*>(field); BStringField* stringField = dynamic_cast<BStringField*>(field);
RatingField* ratingField = dynamic_cast<RatingField*>(field); RatingField* ratingField = dynamic_cast<RatingField*>(field);
if (bitmapField != NULL) { if (packageIconAndTitleField != NULL) {
const BBitmap* bitmap = bitmapField->Bitmap();
// Scale the bitmap to 16x16 // Scale the bitmap to 16x16
BRect r = BRect(0, 0, 15, 15); BRect r = BRect(0, 0, 15, 15);
@@ -357,23 +342,33 @@ PackageColumn::DrawField(BField* field, BRect rect, BView* parent)
break; break;
} }
if (width != bitmapField->Width()) { if (width != packageIconAndTitleField->Width()) {
BString truncatedString(bitmapField->String()); BString truncatedString(packageIconAndTitleField->String());
parent->TruncateString(&truncatedString, fTruncateMode, width + 2); parent->TruncateString(&truncatedString, fTruncateMode, width + 2);
bitmapField->SetClippedString(truncatedString.String()); packageIconAndTitleField->SetClippedString(truncatedString.String());
bitmapField->SetWidth(width); packageIconAndTitleField->SetWidth(width);
} }
// draw the bitmap // draw the bitmap
if (bitmap != NULL) { BitmapRef bitmapRef;
parent->SetDrawingMode(B_OP_ALPHA); status_t bitmapResult;
BRect viewRect(x, y, x + 15, y + 15);
parent->DrawBitmap(bitmap, bitmap->Bounds(), viewRect); bitmapResult = fModel->GetPackageIconRepository().GetIcon(
parent->SetDrawingMode(B_OP_OVER); packageIconAndTitleField->PackageName(), BITMAP_SIZE_16,
bitmapRef);
if (bitmapResult == B_OK) {
if (bitmapRef.Get() != NULL) {
const BBitmap* bitmap = bitmapRef->Bitmap(BITMAP_SIZE_16);
parent->SetDrawingMode(B_OP_ALPHA);
BRect viewRect(x, y, x + 15, y + 15);
parent->DrawBitmap(bitmap, bitmap->Bounds(), viewRect);
parent->SetDrawingMode(B_OP_OVER);
}
} }
// draw the string // draw the string
DrawString(bitmapField->ClippedString(), parent, r); DrawString(packageIconAndTitleField->ClippedString(), parent, r);
} else if (stringField != NULL) { } else if (stringField != NULL) {
@@ -487,22 +482,20 @@ PackageColumn::CompareFields(BField* field1, BField* field2)
float float
PackageColumn::GetPreferredWidth(BField *_field, BView* parent) const PackageColumn::GetPreferredWidth(BField *_field, BView* parent) const
{ {
SharedBitmapStringField* bitmapField PackageIconAndTitleField* packageIconAndTitleField
= dynamic_cast<SharedBitmapStringField*>(_field); = dynamic_cast<PackageIconAndTitleField*>(_field);
BStringField* stringField = dynamic_cast<BStringField*>(_field); BStringField* stringField = dynamic_cast<BStringField*>(_field);
float parentWidth = Inherited::GetPreferredWidth(_field, parent); float parentWidth = Inherited::GetPreferredWidth(_field, parent);
float width = 0.0; float width = 0.0;
if (bitmapField) { if (packageIconAndTitleField) {
const BBitmap* bitmap = bitmapField->Bitmap();
BFont font; BFont font;
parent->GetFont(&font); parent->GetFont(&font);
width = font.StringWidth(bitmapField->String()) + 3 * sTextMargin; width = font.StringWidth(packageIconAndTitleField->String())
if (bitmap) + 3 * sTextMargin;
width += bitmap->Bounds().Width(); width += 16;
else // for the icon; always 16px
width += 16;
} else if (stringField) { } else if (stringField) {
BFont font; BFont font;
parent->GetFont(&font); parent->GetFont(&font);
@@ -558,7 +551,7 @@ PackageRow::PackageRow(const PackageInfoRef& packageRef,
// Package icon and title // Package icon and title
// NOTE: The icon BBitmap is referenced by the fPackage member. // NOTE: The icon BBitmap is referenced by the fPackage member.
UpdateTitle(); UpdateIconAndTitle();
// Rating // Rating
UpdateRating(); UpdateRating();
@@ -590,13 +583,13 @@ PackageRow::~PackageRow()
void void
PackageRow::UpdateTitle() PackageRow::UpdateIconAndTitle()
{ {
if (fPackage.Get() == NULL) if (fPackage.Get() == NULL)
return; return;
SetField(new SharedBitmapStringField(fPackage->Icon(), SetField(new PackageIconAndTitleField(
SharedBitmap::SIZE_16, fPackage->Title()), kTitleColumn); fPackage->Name(), fPackage->Title()), kTitleColumn);
} }
@@ -785,10 +778,10 @@ struct PackageListView::RowByNameHashDefinition {
// #pragma mark - PackageListView // #pragma mark - PackageListView
PackageListView::PackageListView(BLocker* modelLock) PackageListView::PackageListView(Model* model)
: :
BColumnListView(B_TRANSLATE("All packages"), 0, B_FANCY_BORDER, true), BColumnListView(B_TRANSLATE("All packages"), 0, B_FANCY_BORDER, true),
fModelLock(modelLock), fModel(model),
fPackageListener(new(std::nothrow) PackageListener(this)), fPackageListener(new(std::nothrow) PackageListener(this)),
fRowByNameTable(new RowByNameTable()), fRowByNameTable(new RowByNameTable()),
fWorkStatusView(NULL) fWorkStatusView(NULL)
@@ -796,29 +789,33 @@ PackageListView::PackageListView(BLocker* modelLock)
float scale = be_plain_font->Size() / 12.f; float scale = be_plain_font->Size() / 12.f;
float spacing = be_control_look->DefaultItemSpacing() * 2; float spacing = be_control_look->DefaultItemSpacing() * 2;
AddColumn(new PackageColumn(B_TRANSLATE("Name"), 150 * scale, 50 * scale, AddColumn(new PackageColumn(fModel, B_TRANSLATE("Name"),
300 * scale, B_TRUNCATE_MIDDLE), kTitleColumn); 150 * scale, 50 * scale, 300 * scale,
AddColumn(new PackageColumn(B_TRANSLATE("Rating"), 80 * scale, 50 * scale, B_TRUNCATE_MIDDLE), kTitleColumn);
100 * scale, B_TRUNCATE_MIDDLE), kRatingColumn); AddColumn(new PackageColumn(fModel, B_TRANSLATE("Rating"),
AddColumn(new PackageColumn(B_TRANSLATE("Description"), 300 * scale, 80 * scale, 50 * scale, 100 * scale,
80 * scale, 1000 * scale, B_TRUNCATE_MIDDLE), kRatingColumn);
AddColumn(new PackageColumn(fModel, B_TRANSLATE("Description"),
300 * scale, 80 * scale, 1000 * scale,
B_TRUNCATE_MIDDLE), kDescriptionColumn); B_TRUNCATE_MIDDLE), kDescriptionColumn);
PackageColumn* sizeColumn = new PackageColumn(B_TRANSLATE("Size"), PackageColumn* sizeColumn = new PackageColumn(fModel, B_TRANSLATE("Size"),
spacing + StringWidth(B_TRANSLATE("9999.99 KiB")), 50 * scale, spacing + StringWidth(B_TRANSLATE("9999.99 KiB")), 50 * scale,
140 * scale, B_TRUNCATE_END); 140 * scale, B_TRUNCATE_END);
sizeColumn->SetAlignment(B_ALIGN_RIGHT); sizeColumn->SetAlignment(B_ALIGN_RIGHT);
AddColumn(sizeColumn, kSizeColumn); AddColumn(sizeColumn, kSizeColumn);
AddColumn(new PackageColumn(B_TRANSLATE("Status"), AddColumn(new PackageColumn(fModel, B_TRANSLATE("Status"),
spacing + StringWidth(B_TRANSLATE("Available")), 60 * scale, spacing + StringWidth(B_TRANSLATE("Available")), 60 * scale,
140 * scale, B_TRUNCATE_END), kStatusColumn); 140 * scale, B_TRUNCATE_END), kStatusColumn);
AddColumn(new PackageColumn(B_TRANSLATE("Repository"), 120 * scale, AddColumn(new PackageColumn(fModel, B_TRANSLATE("Repository"),
50 * scale, 200 * scale, B_TRUNCATE_MIDDLE), kRepositoryColumn); 120 * scale, 50 * scale, 200 * scale,
B_TRUNCATE_MIDDLE), kRepositoryColumn);
SetColumnVisible(kRepositoryColumn, false); SetColumnVisible(kRepositoryColumn, false);
// invisible by default // invisible by default
AddColumn(new PackageColumn(B_TRANSLATE("Version"), 50 * scale, AddColumn(new PackageColumn(fModel, B_TRANSLATE("Version"),
50 * scale, 200 * scale, B_TRUNCATE_MIDDLE), kVersionColumn); 50 * scale, 50 * scale, 200 * scale,
B_TRUNCATE_MIDDLE), kVersionColumn);
fItemCountView = new ItemCountView(); fItemCountView = new ItemCountView();
AddStatusView(fItemCountView); AddStatusView(fItemCountView);
@@ -864,11 +861,11 @@ PackageListView::MessageReceived(BMessage* message)
break; break;
} }
BAutolock _(fModelLock); BAutolock _(fModel->Lock());
PackageRow* row = _FindRow(name); PackageRow* row = _FindRow(name);
if (row != NULL) { if (row != NULL) {
if ((changes & PKG_CHANGED_TITLE) != 0) if ((changes & PKG_CHANGED_TITLE) != 0)
row->UpdateTitle(); row->UpdateIconAndTitle();
if ((changes & PKG_CHANGED_SUMMARY) != 0) if ((changes & PKG_CHANGED_SUMMARY) != 0)
row->UpdateSummary(); row->UpdateSummary();
if ((changes & PKG_CHANGED_RATINGS) != 0) if ((changes & PKG_CHANGED_RATINGS) != 0)
@@ -878,7 +875,7 @@ PackageListView::MessageReceived(BMessage* message)
if ((changes & PKG_CHANGED_SIZE) != 0) if ((changes & PKG_CHANGED_SIZE) != 0)
row->UpdateSize(); row->UpdateSize();
if ((changes & PKG_CHANGED_ICON) != 0) if ((changes & PKG_CHANGED_ICON) != 0)
row->UpdateTitle(); row->UpdateIconAndTitle();
if ((changes & PKG_CHANGED_DEPOT) != 0) if ((changes & PKG_CHANGED_DEPOT) != 0)
row->UpdateRepository(); row->UpdateRepository();
if ((changes & PKG_CHANGED_VERSION) != 0) if ((changes & PKG_CHANGED_VERSION) != 0)
@@ -927,7 +924,7 @@ PackageListView::AddPackage(const PackageInfoRef& package)
if (packageRow != NULL) if (packageRow != NULL)
return; return;
BAutolock _(fModelLock); BAutolock _(fModel->Lock());
// create the row for this package // create the row for this package
packageRow = new PackageRow(package, fPackageListener); packageRow = new PackageRow(package, fPackageListener);
+4 -2
View File
@@ -1,6 +1,7 @@
/* /*
* Copyright 2013, Stephan Aßmus <superstippi@gmx.de>. * Copyright 2013, Stephan Aßmus <superstippi@gmx.de>.
* Copyright 2013, Rene Gollent <rene@gollent.com>. * Copyright 2013, Rene Gollent <rene@gollent.com>.
* Copyright 2020, Andrew Lindesay <apl@lindesay.co.nz>
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
#ifndef PACKAGE_LIST_VIEW_H #ifndef PACKAGE_LIST_VIEW_H
@@ -12,6 +13,7 @@
#include <Locker.h> #include <Locker.h>
#include <util/OpenHashTable.h> #include <util/OpenHashTable.h>
#include "Model.h"
#include "PackageInfo.h" #include "PackageInfo.h"
@@ -22,7 +24,7 @@ class WorkStatusView;
class PackageListView : public BColumnListView { class PackageListView : public BColumnListView {
public: public:
PackageListView(BLocker* modelLock); PackageListView(Model* model);
virtual ~PackageListView(); virtual ~PackageListView();
virtual void AttachedToWindow(); virtual void AttachedToWindow();
@@ -49,7 +51,7 @@ private:
struct RowByNameHashDefinition; struct RowByNameHashDefinition;
typedef BOpenHashTable<RowByNameHashDefinition> RowByNameTable; typedef BOpenHashTable<RowByNameHashDefinition> RowByNameTable;
BLocker* fModelLock; Model* fModel;
ItemCountView* fItemCountView; ItemCountView* fItemCountView;
PackageListener* fPackageListener; PackageListener* fPackageListener;
RowByNameTable* fRowByNameTable; RowByNameTable* fRowByNameTable;
+2 -2
View File
@@ -154,8 +154,8 @@ protected:
virtual const BBitmap* StarBitmap() virtual const BBitmap* StarBitmap()
{ {
if (fRatingDeterminate) if (fRatingDeterminate)
return fStarBlueBitmap->Bitmap(SharedBitmap::SIZE_16); return fStarBlueBitmap->Bitmap(BITMAP_SIZE_16);
return fStarGrayBitmap->Bitmap(SharedBitmap::SIZE_16); return fStarGrayBitmap->Bitmap(BITMAP_SIZE_16);
} }
private: private:
+2 -2
View File
@@ -57,10 +57,10 @@ ScreenshotWindow::ScreenshotWindow(BWindow* parent, BRect frame)
fToolBar = new BToolBar(); fToolBar = new BToolBar();
fToolBar->AddAction(MSG_PREVIOUS_SCREENSHOT, this, fToolBar->AddAction(MSG_PREVIOUS_SCREENSHOT, this,
sNextButtonIcon->Bitmap(SharedBitmap::SIZE_22), sNextButtonIcon->Bitmap(BITMAP_SIZE_22),
NULL, NULL); NULL, NULL);
fToolBar->AddAction(MSG_NEXT_SCREENSHOT, this, fToolBar->AddAction(MSG_NEXT_SCREENSHOT, this,
sPreviousButtonIcon->Bitmap(SharedBitmap::SIZE_22), sPreviousButtonIcon->Bitmap(BITMAP_SIZE_22),
NULL, NULL); NULL, NULL);
fToolBar->AddView(fIndexView); fToolBar->AddView(fIndexView);
fToolBar->AddGlue(); fToolBar->AddGlue();
@@ -118,7 +118,7 @@ BitmapView::MaxSize()
void void
BitmapView::SetBitmap(SharedBitmap* bitmap, SharedBitmap::Size bitmapSize) BitmapView::SetBitmap(SharedBitmap* bitmap, BitmapSize bitmapSize)
{ {
if (bitmap == fReference && bitmapSize == fBitmapSize) if (bitmap == fReference && bitmapSize == fBitmapSize)
return; return;
+2 -3
View File
@@ -25,14 +25,13 @@ public:
virtual BSize MaxSize(); virtual BSize MaxSize();
void SetBitmap(SharedBitmap* bitmap, void SetBitmap(SharedBitmap* bitmap,
SharedBitmap::Size bitmapSize BitmapSize bitmapSize = BITMAP_SIZE_ANY);
= SharedBitmap::SIZE_ANY);
void UnsetBitmap(); void UnsetBitmap();
void SetScaleBitmap(bool scaleBitmap); void SetScaleBitmap(bool scaleBitmap);
private: private:
BitmapRef fReference; BitmapRef fReference;
SharedBitmap::Size fBitmapSize; BitmapSize fBitmapSize;
const BBitmap* fBitmap; const BBitmap* fBitmap;
bool fScaleBitmap; bool fScaleBitmap;
}; };
@@ -47,8 +47,8 @@ const BBitmap*
RatingView::StarBitmap() RatingView::StarBitmap()
{ {
if (fRating < RATING_MIN) if (fRating < RATING_MIN)
return fStarGrayBitmap->Bitmap(SharedBitmap::SIZE_16); return fStarGrayBitmap->Bitmap(BITMAP_SIZE_16);
return fStarBlueBitmap->Bitmap(SharedBitmap::SIZE_16); return fStarBlueBitmap->Bitmap(BITMAP_SIZE_16);
} }
+47 -33
View File
@@ -75,41 +75,28 @@ SharedBitmap::SharedBitmap(BPositionIO& data)
fSize(0), fSize(0),
fMimeType() fMimeType()
{ {
status_t status = data.GetSize(&fSize); off_t size;
const off_t kMaxSize = 1024 * 1024; if (data.GetSize(&size) == B_OK) {
if (status == B_OK && fSize > 0 && fSize <= kMaxSize) { data.Seek(0, SEEK_SET);
fBuffer = new(std::nothrow) uint8[fSize]; _InitWithData(data, size);
if (fBuffer != NULL) {
data.Seek(0, SEEK_SET);
off_t bytesRead = 0;
size_t chunkSize = std::min((off_t)4096, fSize);
while (bytesRead < fSize) {
ssize_t read = data.Read(fBuffer + bytesRead, chunkSize);
if (read > 0)
bytesRead += read;
else
break;
}
if (bytesRead != fSize) {
delete[] fBuffer;
fBuffer = NULL;
fSize = 0;
}
} else
fSize = 0;
} else {
HDERROR("SharedBitmap(): Stream too large: %" B_PRIi64
", max: %" B_PRIi64, fSize, kMaxSize);
} }
fBitmap[0] = NULL; fBitmap[0] = NULL;
fBitmap[1] = NULL; fBitmap[1] = NULL;
fBitmap[2] = NULL; fBitmap[2] = NULL;
fBitmap[3] = NULL; fBitmap[3] = NULL;
} }
SharedBitmap::SharedBitmap(BDataIO& data, size_t size)
:
BReferenceable(),
fResourceID(-1),
fBuffer(NULL),
fSize(0),
fMimeType()
{
_InitWithData(data, size);
}
SharedBitmap::~SharedBitmap() SharedBitmap::~SharedBitmap()
{ {
@@ -121,8 +108,35 @@ SharedBitmap::~SharedBitmap()
} }
void
SharedBitmap::_InitWithData(BDataIO& data, size_t size)
{
fSize = size;
const off_t kMaxSize = 1024 * 1024;
if (size > 0 && size <= kMaxSize) {
fBuffer = new(std::nothrow) uint8[size];
if (fBuffer != NULL) {
if (data.ReadExactly(fBuffer, size) == B_OK)
fSize = size;
else {
delete[] fBuffer;
fBuffer = NULL;
}
}
} else {
HDERROR("image data too large to deal with; %" B_PRIi64
", max: %" B_PRIi64, fSize, kMaxSize);
}
fBitmap[0] = NULL;
fBitmap[1] = NULL;
fBitmap[2] = NULL;
fBitmap[3] = NULL;
}
const BBitmap* const BBitmap*
SharedBitmap::Bitmap(Size which) SharedBitmap::Bitmap(BitmapSize which)
{ {
if (fResourceID == -1 && fMimeType.Length() == 0 && fBuffer == NULL) if (fResourceID == -1 && fMimeType.Length() == 0 && fBuffer == NULL)
return fBitmap[0]; return fBitmap[0];
@@ -132,20 +146,20 @@ SharedBitmap::Bitmap(Size which)
switch (which) { switch (which) {
default: default:
case SIZE_16: case BITMAP_SIZE_16:
break; break;
case SIZE_22: case BITMAP_SIZE_22:
index = 1; index = 1;
size = 22; size = 22;
break; break;
case SIZE_32: case BITMAP_SIZE_32:
index = 2; index = 2;
size = 32; size = 32;
break; break;
case SIZE_64: case BITMAP_SIZE_64:
index = 3; index = 3;
size = 64; size = 64;
break; break;
@@ -1,5 +1,6 @@
/* /*
* Copyright 2013-2014, Stephan Aßmus <superstippi@gmx.de>. * Copyright 2013-2014, Stephan Aßmus <superstippi@gmx.de>.
* Copyright 2020, Andrew Lindesay <apl@lindesay.co.nz>
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
#ifndef SHARED_BITMAP_H #ifndef SHARED_BITMAP_H
@@ -9,32 +10,28 @@
#include <Referenceable.h> #include <Referenceable.h>
#include <String.h> #include <String.h>
#include "HaikuDepotConstants.h"
#include "List.h" #include "List.h"
class BBitmap; class BBitmap;
class BDataIO;
class BPositionIO; class BPositionIO;
class SharedBitmap : public BReferenceable { class SharedBitmap : public BReferenceable {
public: public:
enum Size {
SIZE_ANY = -1,
SIZE_16 = 0,
SIZE_22 = 1,
SIZE_32 = 2,
SIZE_64 = 3
};
SharedBitmap(BBitmap* bitmap); SharedBitmap(BBitmap* bitmap);
SharedBitmap(int32 resourceID); SharedBitmap(int32 resourceID);
SharedBitmap(const char* mimeType); SharedBitmap(const char* mimeType);
SharedBitmap(BPositionIO& data); SharedBitmap(BPositionIO& data);
SharedBitmap(BDataIO& data, size_t size);
~SharedBitmap(); ~SharedBitmap();
const BBitmap* Bitmap(Size which); const BBitmap* Bitmap(BitmapSize which);
private: private:
void _InitWithData(BDataIO& data, size_t size);
BBitmap* _CreateBitmapFromResource(int32 size) const; BBitmap* _CreateBitmapFromResource(int32 size) const;
BBitmap* _CreateBitmapFromBuffer(int32 size) const; BBitmap* _CreateBitmapFromBuffer(int32 size) const;
BBitmap* _CreateBitmapFromMimeType(int32 size) const; BBitmap* _CreateBitmapFromMimeType(int32 size) const;
+57 -17
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2018, Andrew Lindesay <apl@lindesay.co.nz>. * Copyright 2018-2020, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
#include "DataIOUtils.h" #include "DataIOUtils.h"
@@ -8,26 +8,66 @@
#define BUFFER_SIZE 1024 #define BUFFER_SIZE 1024
status_t /*static*/ status_t
DataIOUtils::Copy(BDataIO* target, BDataIO* source, size_t size) DataIOUtils::CopyAll(BDataIO* target, BDataIO* source)
{ {
status_t result = B_OK; status_t result = B_OK;
uint8 buffer[BUFFER_SIZE]; uint8 buffer[BUFFER_SIZE];
size_t sizeRead = 0;
while (size > 0 && result == B_OK) { do {
size_t sizeToRead = size; result = source->ReadExactly(buffer, BUFFER_SIZE, &sizeRead);
size_t sizeRead = 0;
if (sizeToRead > BUFFER_SIZE) switch (result)
sizeToRead = BUFFER_SIZE; {
case B_OK:
result = source->ReadExactly(buffer, sizeToRead, &sizeRead); case B_PARTIAL_READ:
result = target->WriteExactly(buffer, sizeRead);
if (result == B_OK) break;
result = target->WriteExactly(buffer, sizeRead); }
} while(result == B_OK && sizeRead > 0);
size -= sizeRead;
}
return result; return result;
} }
ConstraintedDataIO::ConstraintedDataIO(BDataIO* delegate, size_t limit)
:
fDelegate(delegate),
fLimit(limit)
{
}
ConstraintedDataIO::~ConstraintedDataIO()
{
}
ssize_t
ConstraintedDataIO::Read(void* buffer, size_t size)
{
if (size > fLimit)
size = fLimit;
ssize_t actualRead = fDelegate->Read(buffer, size);
if (actualRead > 0)
fLimit -= actualRead;
return actualRead;
}
ssize_t
ConstraintedDataIO::Write(const void* buffer, size_t size)
{
return B_NOT_SUPPORTED;
}
status_t
ConstraintedDataIO::Flush()
{
return B_OK;
}
+26 -3
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2018, Andrew Lindesay <apl@lindesay.co.nz>. * Copyright 2018-2020, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License. * All rights reserved. Distributed under the terms of the MIT License.
*/ */
#ifndef DATA_IO_UTILS_H #ifndef DATA_IO_UTILS_H
@@ -10,10 +10,33 @@
class DataIOUtils { class DataIOUtils {
public: public:
static status_t Copy(BDataIO* target, BDataIO* source, size_t size); static status_t CopyAll(BDataIO* target, BDataIO* source);
};
/*! This is a data source (read only) that is restricted to a certain size. An
example of where this is used is with reading out the data from a tar
stream. The tar logic knows how long the data is and so is able to provide
a client this constrained view of the data that is only able to read a
constrained quantity of data from the delegate data source. This prevents
overflow reads from the tar file.
*/
class ConstraintedDataIO : public BDataIO {
public:
ConstraintedDataIO(BDataIO* delegate,
size_t limit);
virtual ~ConstraintedDataIO();
virtual ssize_t Read(void* buffer, size_t size);
virtual ssize_t Write(const void* buffer, size_t size);
virtual status_t Flush();
private:
BDataIO* fDelegate;
size_t fLimit;
}; };
+2 -2
View File
@@ -22,9 +22,9 @@ RatingUtils::Draw(BView* target, BPoint at, float value)
const BBitmap* star; const BBitmap* star;
if (value < RATING_MIN) if (value < RATING_MIN)
star = sStarGrayBitmap->Bitmap(SharedBitmap::SIZE_16); star = sStarGrayBitmap->Bitmap(BITMAP_SIZE_16);
else else
star = sStarBlueBitmap->Bitmap(SharedBitmap::SIZE_16); star = sStarBlueBitmap->Bitmap(BITMAP_SIZE_16);
if (star == NULL) { if (star == NULL) {
debugger("no star icon found in application resources."); debugger("no star icon found in application resources.");
+28
View File
@@ -278,3 +278,31 @@ StorageUtils::LocalWorkingDirectoryPath(const BString leaf, BPath& path,
return result; return result;
} }
/*static*/ status_t
StorageUtils::SwapExtensionOnPath(BPath& path, const char* extension)
{
BPath parent;
status_t result = path.GetParent(&parent);
if (result == B_OK) {
path.SetTo(parent.Path(),
SwapExtensionOnPathComponent(path.Leaf(), extension).String());
}
return result;
}
/*static*/ BString
StorageUtils::SwapExtensionOnPathComponent(const char* pathComponent,
const char* extension)
{
BString result(pathComponent);
int32 lastDot = result.FindLast(".");
if (lastDot != B_ERROR) {
result.Truncate(lastDot);
}
result.Append(".");
result.Append(extension);
return result;
}
+6
View File
@@ -28,6 +28,12 @@ public:
bool* exists, bool* exists,
bool* isDirectory, bool* isDirectory,
off_t* size); off_t* size);
static status_t SwapExtensionOnPath(BPath& path,
const char* extension);
static BString SwapExtensionOnPathComponent(
const char* pathComponent,
const char* extension);
}; };
#endif // PATH_UTILS_H #endif // PATH_UTILS_H
@@ -1,5 +1,5 @@
/* /*
* Copyright 2017-2019, Andrew Lindesay, apl@lindesay.co.nz * Copyright 2017-2020, Andrew Lindesay, apl@lindesay.co.nz
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
@@ -10,6 +10,8 @@
#include "DumpExportRepositoryJsonListenerTest.h" #include "DumpExportRepositoryJsonListenerTest.h"
#include "ValidationFailureTest.h" #include "ValidationFailureTest.h"
#include "ValidationUtilsTest.h" #include "ValidationUtilsTest.h"
#include "StorageUtilsTest.h"
#include "TarArchiveServiceTest.h"
#include "ListTest.h" #include "ListTest.h"
BTestSuite* BTestSuite*
@@ -22,6 +24,8 @@ getTestSuite()
ValidationFailureTest::AddTests(*suite); ValidationFailureTest::AddTests(*suite);
ValidationUtilsTest::AddTests(*suite); ValidationUtilsTest::AddTests(*suite);
ListTest::AddTests(*suite); ListTest::AddTests(*suite);
StorageUtilsTest::AddTests(*suite);
TarArchiveServiceTest::AddTests(*suite);
return suite; return suite;
} }
+10
View File
@@ -15,6 +15,7 @@ local sourceDirs =
server server
server/dumpexportrepository server/dumpexportrepository
util util
tar
textview textview
edits_generic edits_generic
; ;
@@ -31,6 +32,8 @@ SEARCH_SOURCE += [ FDirName $(HAIKUDEPOT_GENERATED_SOURCES_DIRECTORY)
UnitTestLib haikudepottest.so : UnitTestLib haikudepottest.so :
HaikuDepotTestAddon.cpp HaikuDepotTestAddon.cpp
DataIOUtils.cpp
DumpExportRepositorySource.cpp DumpExportRepositorySource.cpp
DumpExportRepositorySourceMirror.cpp DumpExportRepositorySourceMirror.cpp
DumpExportRepository.cpp DumpExportRepository.cpp
@@ -45,6 +48,13 @@ UnitTestLib haikudepottest.so :
StandardMetaDataJsonEventListener.cpp StandardMetaDataJsonEventListener.cpp
StandardMetaDataJsonEventListenerTest.cpp StandardMetaDataJsonEventListenerTest.cpp
StorageUtils.cpp
StorageUtilsTest.cpp
TarArchiveHeader.cpp
TarArchiveService.cpp
TarArchiveServiceTest.cpp
ValidationFailure.cpp ValidationFailure.cpp
ValidationFailureTest.cpp ValidationFailureTest.cpp
@@ -0,0 +1,50 @@
/*
* Copyright 2020, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "StorageUtilsTest.h"
#include <String.h>
#include <cppunit/TestCaller.h>
#include <cppunit/TestSuite.h>
#include "StorageUtils.h"
StorageUtilsTest::StorageUtilsTest()
{
}
StorageUtilsTest::~StorageUtilsTest()
{
}
void
StorageUtilsTest::TestSwapExtensionOnPathComponent()
{
const BString input = "/paved/path.tea";
// ----------------------
BString output = StorageUtils::SwapExtensionOnPathComponent(input, "chai");
// ----------------------
const BString expected = "/paved/path.chai";
CPPUNIT_ASSERT_EQUAL(expected, output);
}
/*static*/ void
StorageUtilsTest::AddTests(BTestSuite& parent)
{
CppUnit::TestSuite& suite = *new CppUnit::TestSuite("StorageUtilsTest");
suite.addTest(
new CppUnit::TestCaller<StorageUtilsTest>(
"StorageUtilsTest::TestSwapExtensionOnPathComponent",
&StorageUtilsTest::TestSwapExtensionOnPathComponent));
parent.addTest("StorageUtilsTest", &suite);
}
@@ -0,0 +1,23 @@
/*
* Copyright 2020, Andrew Lindesay <apl@lindesay.co.nz>
* Distributed under the terms of the MIT License.
*/
#ifndef STORAGE_UTILS_TEST_H
#define STORAGE_UTILS_TEST_H
#include <TestCase.h>
#include <TestSuite.h>
class StorageUtilsTest : public CppUnit::TestCase {
public:
StorageUtilsTest();
virtual ~StorageUtilsTest();
void TestSwapExtensionOnPathComponent();
static void AddTests(BTestSuite& suite);
};
#endif // STORAGE_UTILS_TEST_H
@@ -0,0 +1,102 @@
/*
* Copyright 2020, Andrew Lindesay <apl@lindesay.co.nz>.
* All rights reserved. Distributed under the terms of the MIT License.
*/
#include "TarArchiveServiceTest.h"
#include <stdlib.h>
#include <AutoDeleter.h>
#include <File.h>
#include <String.h>
#include <cppunit/TestCaller.h>
#include <cppunit/TestSuite.h>
#include "TarArchiveHeader.h"
#include "TarArchiveService.h"
#include "TarArchiveServiceTestSample.h"
TarArchiveServiceTest::TarArchiveServiceTest()
{
}
TarArchiveServiceTest::~TarArchiveServiceTest()
{
}
void
TarArchiveServiceTest::TestReadHeader()
{
BString tarPath;
if (CreateSampleFile(tarPath) != B_OK) {
printf("! unable to setup the sample tar --> exit");
exit(1);
}
BFile *tarFile = new BFile(tarPath, O_RDONLY);
tarFile->Seek(2048, SEEK_SET);
// known offset in the same data
TarArchiveHeader header;
// ----------------------
status_t result = TarArchiveService::GetEntry(*tarFile, header);
// ----------------------
CPPUNIT_ASSERT_EQUAL(B_OK, result);
CPPUNIT_ASSERT_EQUAL(BString("hicn/somepkg/16.png"), header.FileName());
CPPUNIT_ASSERT_EQUAL(657, header.Length());
CPPUNIT_ASSERT_EQUAL(TAR_FILE_TYPE_NORMAL, header.FileType());
delete tarFile;
DeleteSampleFile(tarPath);
}
/*! This method will store the tar file sample into a temporary file and will
return the pathname to that file.
*/
status_t
TarArchiveServiceTest::CreateSampleFile(BString& path)
{
path.SetTo(tmpnam(NULL));
BFile* file = new BFile(path, O_WRONLY | O_CREAT);
ObjectDeleter<BFile> tarIoDeleter(file);
status_t result = file->WriteExactly(kSampleTarPayload, kSampleTarLength);
if (result != B_OK) {
printf("! unable to write the sample data to [%s]\n", path.String());
}
return result;
}
status_t
TarArchiveServiceTest::DeleteSampleFile(const BString& path)
{
if (remove(path.String()) != 0)
return B_ERROR;
return B_OK;
}
/*static*/ void
TarArchiveServiceTest::AddTests(BTestSuite& parent)
{
CppUnit::TestSuite& suite = *new CppUnit::TestSuite("TarArchiveServiceTest");
suite.addTest(
new CppUnit::TestCaller<TarArchiveServiceTest>(
"TarArchiveServiceTest::TestReadHeader",
&TarArchiveServiceTest::TestReadHeader));
parent.addTest("TarArchiveServiceTest", &suite);
}
@@ -0,0 +1,28 @@
/*
* Copyright 2020, Andrew Lindesay <apl@lindesay.co.nz>
* Distributed under the terms of the MIT License.
*/
#ifndef TAR_ARCHIVE_SERVICE_TEST_H
#define TAR_ARCHIVE_SERVICE_TEST_H
#include "String.h"
#include <TestCase.h>
#include <TestSuite.h>
class TarArchiveServiceTest : public CppUnit::TestCase {
public:
TarArchiveServiceTest();
virtual ~TarArchiveServiceTest();
void TestReadHeader();
static void AddTests(BTestSuite& suite);
private:
status_t CreateSampleFile(BString& path);
status_t DeleteSampleFile(const BString& path);
};
#endif // TAR_ARCHIVE_SERVICE_TEST_H
@@ -0,0 +1,876 @@
/*
* Copyright 2020, Andrew Lindesay <apl@lindesay.co.nz>
* Distributed under the terms of the MIT License.
*/
// This file contains sample data for the testing of the TarArchiveService.
// -----
// The following tar data contains a structure similar to that which would be
// returned from HDS when it provides a dump of all of the icons in the system.
// The tar contains the following files and (file-lengths) and (offsets);
//
// hicn/ (0) (0)
// hicn/info.json (212) (512)
// hicn/somepkg/ (0) (1536)
// hicn/somepkg/16.png (657) (2048)
// hicn/somepkg/icon.hvif (64) (3584)
// hicn/somepkg/32.png (1160) (4608)
unsigned char kSampleTarPayload[] = {
0x68, 0x69, 0x63, 0x6e, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x37, 0x37, 0x35, 0x00,
0x30, 0x30, 0x30, 0x31, 0x37, 0x35, 0x30, 0x00, 0x30, 0x30, 0x30, 0x31,
0x37, 0x35, 0x30, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x00, 0x31, 0x33, 0x37, 0x32, 0x36, 0x31, 0x33, 0x32,
0x36, 0x36, 0x33, 0x00, 0x30, 0x31, 0x32, 0x35, 0x34, 0x30, 0x00, 0x20,
0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x73, 0x74, 0x61, 0x72, 0x20, 0x20,
0x00, 0x61, 0x6e, 0x64, 0x70, 0x6f, 0x6e, 0x6c, 0x69, 0x6e, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x6e, 0x64,
0x70, 0x6f, 0x6e, 0x6c, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x69, 0x63, 0x6e,
0x2f, 0x69, 0x6e, 0x66, 0x6f, 0x2e, 0x6a, 0x73, 0x6f, 0x6e, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x30, 0x30, 0x30, 0x30, 0x36, 0x36, 0x34, 0x00, 0x30, 0x30, 0x30, 0x31,
0x37, 0x35, 0x30, 0x00, 0x30, 0x30, 0x30, 0x31, 0x37, 0x35, 0x30, 0x00,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x33, 0x32, 0x34, 0x00,
0x31, 0x33, 0x37, 0x32, 0x36, 0x31, 0x33, 0x32, 0x36, 0x36, 0x33, 0x00,
0x30, 0x31, 0x34, 0x33, 0x36, 0x35, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x75, 0x73, 0x74, 0x61, 0x72, 0x20, 0x20, 0x00, 0x61, 0x6e, 0x64,
0x70, 0x6f, 0x6e, 0x6c, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x6e, 0x64, 0x70, 0x6f, 0x6e, 0x6c,
0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x7b, 0x22, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65,
0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x3a, 0x31,
0x35, 0x39, 0x39, 0x31, 0x32, 0x37, 0x37, 0x39, 0x30, 0x39, 0x32, 0x34,
0x2c, 0x22, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65,
0x73, 0x74, 0x61, 0x6d, 0x70, 0x49, 0x73, 0x6f, 0x22, 0x3a, 0x22, 0x32,
0x30, 0x32, 0x30, 0x2d, 0x30, 0x39, 0x2d, 0x30, 0x33, 0x20, 0x31, 0x30,
0x3a, 0x30, 0x39, 0x3a, 0x35, 0x30, 0x22, 0x2c, 0x22, 0x64, 0x61, 0x74,
0x61, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x54, 0x69, 0x6d,
0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x3a, 0x31, 0x35, 0x39, 0x36,
0x39, 0x35, 0x36, 0x30, 0x35, 0x31, 0x30, 0x30, 0x30, 0x2c, 0x22, 0x64,
0x61, 0x74, 0x61, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x54,
0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x49, 0x73, 0x6f, 0x22,
0x3a, 0x22, 0x32, 0x30, 0x32, 0x30, 0x2d, 0x30, 0x38, 0x2d, 0x30, 0x39,
0x20, 0x30, 0x36, 0x3a, 0x35, 0x34, 0x3a, 0x31, 0x31, 0x22, 0x2c, 0x22,
0x61, 0x67, 0x65, 0x6e, 0x74, 0x22, 0x3a, 0x22, 0x68, 0x64, 0x73, 0x22,
0x2c, 0x22, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69,
0x6f, 0x6e, 0x22, 0x3a, 0x22, 0x31, 0x2e, 0x30, 0x2e, 0x31, 0x32, 0x32,
0x2d, 0x53, 0x4e, 0x41, 0x50, 0x53, 0x48, 0x4f, 0x54, 0x22, 0x7d, 0x0a,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x68, 0x69, 0x63, 0x6e, 0x2f, 0x73, 0x6f, 0x6d, 0x65, 0x70, 0x6b, 0x67,
0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x37, 0x37, 0x35, 0x00,
0x30, 0x30, 0x30, 0x31, 0x37, 0x35, 0x30, 0x00, 0x30, 0x30, 0x30, 0x31,
0x37, 0x35, 0x30, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x00, 0x31, 0x33, 0x37, 0x32, 0x36, 0x31, 0x33, 0x32,
0x33, 0x36, 0x32, 0x00, 0x30, 0x31, 0x34, 0x32, 0x30, 0x31, 0x00, 0x20,
0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x73, 0x74, 0x61, 0x72, 0x20, 0x20,
0x00, 0x61, 0x6e, 0x64, 0x70, 0x6f, 0x6e, 0x6c, 0x69, 0x6e, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x6e, 0x64,
0x70, 0x6f, 0x6e, 0x6c, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x69, 0x63, 0x6e,
0x2f, 0x73, 0x6f, 0x6d, 0x65, 0x70, 0x6b, 0x67, 0x2f, 0x31, 0x36, 0x2e,
0x70, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x30, 0x30, 0x30, 0x30, 0x36, 0x34, 0x34, 0x00, 0x30, 0x30, 0x30, 0x31,
0x37, 0x35, 0x30, 0x00, 0x30, 0x30, 0x30, 0x31, 0x37, 0x35, 0x30, 0x00,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x32, 0x32, 0x31, 0x00,
0x31, 0x33, 0x37, 0x32, 0x36, 0x31, 0x33, 0x32, 0x33, 0x35, 0x35, 0x00,
0x30, 0x31, 0x35, 0x31, 0x33, 0x31, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x75, 0x73, 0x74, 0x61, 0x72, 0x20, 0x20, 0x00, 0x61, 0x6e, 0x64,
0x70, 0x6f, 0x6e, 0x6c, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x6e, 0x64, 0x70, 0x6f, 0x6e, 0x6c,
0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x10,
0x00, 0x00, 0x00, 0x10, 0x08, 0x03, 0x00, 0x00, 0x00, 0x28, 0x2d, 0x0f,
0x53, 0x00, 0x00, 0x00, 0x03, 0x73, 0x42, 0x49, 0x54, 0x08, 0x08, 0x08,
0xdb, 0xe1, 0x4f, 0xe0, 0x00, 0x00, 0x01, 0x32, 0x50, 0x4c, 0x54, 0x45,
0x30, 0x0b, 0x3e, 0xe1, 0xb5, 0xf1, 0xb2, 0x42, 0xdb, 0x8e, 0x22, 0xb6,
0x7f, 0x7f, 0x7f, 0xc9, 0x7b, 0xe6, 0x92, 0x92, 0x92, 0x66, 0x66, 0x66,
0xff, 0xff, 0xff, 0x7f, 0x1e, 0xa2, 0x6d, 0x1a, 0x8b, 0xd9, 0xd9, 0xd9,
0xe5, 0xe5, 0xe5, 0xc5, 0xc5, 0xc5, 0x65, 0x18, 0x81, 0xbe, 0x60, 0xe0,
0x91, 0x68, 0xa0, 0xac, 0x33, 0xd8, 0xd9, 0xa1, 0xed, 0x45, 0x45, 0x45,
0xa0, 0x26, 0xcc, 0xf9, 0xf9, 0xf9, 0x4d, 0x12, 0x63, 0x8a, 0x6a, 0x96,
0xe8, 0xc6, 0xf4, 0x6d, 0x4a, 0x7a, 0xb1, 0xb1, 0xb1, 0x4c, 0x12, 0x62,
0xf4, 0xf4, 0xf4, 0xb8, 0x51, 0xdd, 0xab, 0xab, 0xab, 0xd4, 0xd4, 0xd4,
0xc2, 0x69, 0xe2, 0x8e, 0x2c, 0xb1, 0x97, 0x24, 0xc1, 0xed, 0xd4, 0xf6,
0xa8, 0x29, 0xd6, 0xcf, 0x8b, 0xe8, 0xdd, 0xac, 0xef, 0xe4, 0xbd, 0xf2,
0xae, 0x38, 0xd9, 0x87, 0x20, 0xad, 0x73, 0x1c, 0x93, 0xb5, 0x49, 0xdc,
0xba, 0x55, 0xde, 0x84, 0x2a, 0xa5, 0x93, 0x72, 0xa0, 0xc4, 0x6e, 0xe3,
0x75, 0x55, 0x81, 0xc0, 0x66, 0xe1, 0x6b, 0x1a, 0x88, 0x54, 0x14, 0x6b,
0xb0, 0x3d, 0xda, 0xaa, 0x2e, 0xd7, 0xcc, 0x81, 0xe7, 0x9a, 0x25, 0xc5,
0x6a, 0x6a, 0x6a, 0xe7, 0xc4, 0xf3, 0x90, 0x6b, 0x9e, 0x77, 0x1d, 0x98,
0xc7, 0x75, 0xe4, 0x96, 0x69, 0xa6, 0xdf, 0xb0, 0xf0, 0xf0, 0xda, 0xf8,
0xd2, 0x91, 0xea, 0x71, 0x1b, 0x91, 0xb6, 0x4c, 0xdc, 0x92, 0x23, 0xbb,
0xb9, 0x54, 0xde, 0x9d, 0x26, 0xc8, 0xfb, 0xfb, 0xfb, 0x83, 0x1f, 0xa7,
0xb3, 0x46, 0xdb, 0xbb, 0x58, 0xdf, 0xda, 0xa5, 0xed, 0x6f, 0x1b, 0x8e,
0xad, 0x36, 0xd8, 0xe9, 0xc9, 0xf4, 0xab, 0x32, 0xd7, 0xf7, 0xf7, 0xf7,
0xc3, 0x6d, 0xe3, 0xaf, 0x3c, 0xd9, 0xb1, 0x41, 0xda, 0xcd, 0x84, 0xe7,
0xa2, 0x27, 0xcf, 0xb9, 0x50, 0xdf, 0x99, 0x24, 0xc3, 0xc1, 0x66, 0xe3,
0xaf, 0x3a, 0xd9, 0xb5, 0x4a, 0xdc, 0xac, 0x34, 0xd8, 0xb3, 0x44, 0xdb,
0xba, 0x56, 0xdf, 0xe1, 0xb7, 0xf1, 0xc3, 0x6a, 0xe3, 0xa8, 0x2a, 0xd6,
0xb0, 0x3e, 0xda, 0xe7, 0xc5, 0xf3, 0xdf, 0xb3, 0xf1, 0xb7, 0x4e, 0xdd,
0xb5, 0x46, 0xdb, 0xe9, 0xcb, 0xf5, 0xf3, 0x42, 0xfd, 0x0e, 0x00, 0x00,
0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x12, 0x00, 0x00,
0x0b, 0x12, 0x01, 0xd2, 0xdd, 0x7e, 0xfc, 0x00, 0x00, 0x00, 0x1c, 0x74,
0x45, 0x58, 0x74, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x00,
0x41, 0x64, 0x6f, 0x62, 0x65, 0x20, 0x46, 0x69, 0x72, 0x65, 0x77, 0x6f,
0x72, 0x6b, 0x73, 0x20, 0x43, 0x53, 0x35, 0x71, 0xb5, 0xe3, 0x36, 0x00,
0x00, 0x00, 0xce, 0x49, 0x44, 0x41, 0x54, 0x18, 0x95, 0x63, 0xe0, 0x40,
0x03, 0x0c, 0x60, 0xd2, 0xdf, 0xd6, 0x43, 0x8f, 0x1b, 0x49, 0x40, 0x3e,
0xde, 0xd7, 0x57, 0x8d, 0x5f, 0x97, 0x17, 0x2e, 0xa0, 0x62, 0xaf, 0xac,
0xae, 0x26, 0x64, 0xc3, 0x02, 0x17, 0x70, 0x8e, 0x51, 0xf5, 0xf2, 0xd2,
0xf7, 0x81, 0x0b, 0xb8, 0x29, 0xb9, 0x44, 0x9a, 0x24, 0xfb, 0x04, 0x41,
0x05, 0xfc, 0x05, 0x4c, 0xcd, 0x3d, 0x65, 0x23, 0xa3, 0x02, 0xb5, 0x19,
0x40, 0xe6, 0x32, 0xc8, 0x2b, 0x25, 0x59, 0x72, 0x7a, 0x7a, 0xca, 0x46,
0x7b, 0x38, 0x0b, 0x32, 0x29, 0xf2, 0x72, 0x30, 0x98, 0xab, 0x4b, 0x48,
0xd8, 0x25, 0x98, 0xcb, 0x46, 0x32, 0x6b, 0x98, 0x31, 0x86, 0xb3, 0x70,
0x30, 0xb8, 0x2a, 0x38, 0x30, 0x5a, 0xf2, 0x8b, 0xb9, 0x5b, 0xfb, 0x05,
0x33, 0xea, 0x18, 0x01, 0x05, 0x42, 0x0c, 0x0d, 0x0d, 0x65, 0xb5, 0xf8,
0x34, 0x3d, 0x0c, 0xf5, 0x9d, 0x8c, 0x40, 0x02, 0x51, 0x01, 0x86, 0x86,
0x81, 0x5a, 0x8e, 0x9a, 0x9e, 0xfa, 0xfa, 0x81, 0x46, 0x46, 0xc2, 0x32,
0x0c, 0x22, 0xac, 0x71, 0x40, 0x01, 0x63, 0x2e, 0x59, 0x90, 0x80, 0x98,
0x85, 0x14, 0x03, 0x8f, 0x95, 0x29, 0x7f, 0xa0, 0xb1, 0x05, 0x9b, 0x41,
0x88, 0x61, 0xa0, 0x18, 0xbb, 0x9c, 0x28, 0xd0, 0x61, 0x3c, 0xe2, 0xde,
0x16, 0x72, 0xa2, 0x1c, 0x3c, 0x92, 0xde, 0x40, 0x3e, 0xc4, 0xe9, 0xa2,
0x10, 0x8f, 0x82, 0x29, 0x00, 0xe6, 0xfb, 0x21, 0xfd, 0x7c, 0x2e, 0x82,
0xe5, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60,
0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x69, 0x63, 0x6e,
0x2f, 0x73, 0x6f, 0x6d, 0x65, 0x70, 0x6b, 0x67, 0x2f, 0x69, 0x63, 0x6f,
0x6e, 0x2e, 0x68, 0x76, 0x69, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x30, 0x30, 0x30, 0x30, 0x36, 0x34, 0x34, 0x00, 0x30, 0x30, 0x30, 0x31,
0x37, 0x35, 0x30, 0x00, 0x30, 0x30, 0x30, 0x31, 0x37, 0x35, 0x30, 0x00,
0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x30, 0x00,
0x31, 0x33, 0x37, 0x32, 0x36, 0x31, 0x33, 0x32, 0x33, 0x32, 0x31, 0x00,
0x30, 0x31, 0x35, 0x37, 0x36, 0x37, 0x00, 0x20, 0x30, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x75, 0x73, 0x74, 0x61, 0x72, 0x20, 0x20, 0x00, 0x61, 0x6e, 0x64,
0x70, 0x6f, 0x6e, 0x6c, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x6e, 0x64, 0x70, 0x6f, 0x6e, 0x6c,
0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x6e, 0x63, 0x69, 0x66, 0x01, 0x03, 0xff, 0xaa,
0x00, 0x01, 0x02, 0x07, 0x38, 0x2d, 0x42, 0x25, 0x2e, 0x35, 0x2c, 0x40,
0x29, 0x3d, 0x2f, 0x43, 0x38, 0x44, 0x36, 0x3f, 0x3a, 0x49, 0x33, 0x50,
0x2d, 0x4b, 0x39, 0x55, 0x57, 0x4a, 0x54, 0x53, 0x5a, 0x41, 0x50, 0x3e,
0x51, 0x42, 0x4f, 0x3a, 0xc5, 0xfd, 0xb9, 0x33, 0xc7, 0x73, 0xbc, 0x37,
0x4c, 0x28, 0x01, 0x0a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x68, 0x69, 0x63, 0x6e, 0x2f, 0x73, 0x6f, 0x6d, 0x65, 0x70, 0x6b, 0x67,
0x2f, 0x33, 0x32, 0x2e, 0x70, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, 0x36, 0x34, 0x34, 0x00,
0x30, 0x30, 0x30, 0x31, 0x37, 0x35, 0x30, 0x00, 0x30, 0x30, 0x30, 0x31,
0x37, 0x35, 0x30, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x32,
0x32, 0x31, 0x30, 0x00, 0x31, 0x33, 0x37, 0x32, 0x36, 0x31, 0x33, 0x32,
0x33, 0x36, 0x32, 0x00, 0x30, 0x31, 0x35, 0x31, 0x32, 0x34, 0x00, 0x20,
0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x73, 0x74, 0x61, 0x72, 0x20, 0x20,
0x00, 0x61, 0x6e, 0x64, 0x70, 0x6f, 0x6e, 0x6c, 0x69, 0x6e, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x6e, 0x64,
0x70, 0x6f, 0x6e, 0x6c, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x50, 0x4e, 0x47,
0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x08, 0x03, 0x00, 0x00,
0x00, 0x44, 0xa4, 0x8a, 0xc6, 0x00, 0x00, 0x00, 0x03, 0x73, 0x42, 0x49,
0x54, 0x08, 0x08, 0x08, 0xdb, 0xe1, 0x4f, 0xe0, 0x00, 0x00, 0x01, 0xec,
0x50, 0x4c, 0x54, 0x45, 0x00, 0x00, 0x00, 0xb6, 0x90, 0xea, 0x6d, 0x27,
0xcf, 0x66, 0x66, 0x66, 0x48, 0x1a, 0x88, 0xfa, 0xfa, 0xfa, 0x99, 0x65,
0xe1, 0x2c, 0x10, 0x54, 0xd7, 0xc3, 0xf3, 0xd4, 0xd4, 0xd4, 0x51, 0x51,
0x51, 0x99, 0x99, 0x99, 0x86, 0x49, 0xdc, 0x17, 0x17, 0x17, 0xe4, 0xd7,
0xf7, 0x4e, 0x1c, 0x93, 0x29, 0x29, 0x29, 0xac, 0x81, 0xe7, 0xcb, 0xb1,
0xf0, 0x53, 0x1e, 0x9e, 0xa0, 0xa0, 0xa0, 0x3a, 0x14, 0x6e, 0x84, 0x84,
0x84, 0x7e, 0x3c, 0xda, 0x8d, 0x54, 0xde, 0x9e, 0x6c, 0xe3, 0x20, 0x0b,
0x3e, 0x14, 0x14, 0x14, 0xf0, 0xf0, 0xf0, 0x83, 0x83, 0x83, 0xa9, 0xa9,
0xa9, 0x7e, 0x7e, 0x7e, 0x77, 0x32, 0xd8, 0xc2, 0xa3, 0xed, 0x36, 0x13,
0x68, 0x24, 0x24, 0x24, 0x60, 0x22, 0xb6, 0x7b, 0x7b, 0x7b, 0x2b, 0x16,
0x47, 0xa2, 0x72, 0xe4, 0x93, 0x5c, 0xe0, 0xef, 0xef, 0xef, 0x3a, 0x3a,
0x3a, 0xd1, 0xba, 0xf1, 0x1c, 0x1c, 0x1c, 0x3e, 0x16, 0x76, 0xb7, 0xb7,
0xb7, 0x81, 0x42, 0xda, 0xff, 0xff, 0xff, 0xe5, 0xe5, 0xe5, 0xbd, 0x9b,
0xec, 0x8a, 0x4e, 0xdd, 0xdd, 0xcb, 0xf5, 0x4a, 0x1a, 0x8d, 0x59, 0x20,
0xaa, 0x05, 0x05, 0x05, 0x7b, 0x38, 0xd9, 0x34, 0x12, 0x63, 0x45, 0x18,
0x83, 0xc7, 0xab, 0xee, 0xe9, 0xdf, 0xf8, 0x9b, 0x68, 0xe2, 0xf5, 0xf5,
0xf5, 0x77, 0x32, 0xd7, 0xb2, 0xb2, 0xb2, 0xdf, 0xdf, 0xdf, 0xd0, 0xb9,
0xf1, 0x91, 0x59, 0xdf, 0xa9, 0x7d, 0xe6, 0xaf, 0x87, 0xe8, 0x8a, 0x8a,
0x8a, 0xd5, 0xc0, 0xf3, 0xbc, 0x9b, 0xeb, 0x20, 0x20, 0x20, 0x84, 0x46,
0xdb, 0x9e, 0x9e, 0x9e, 0xc1, 0xa1, 0xed, 0x4f, 0x1c, 0x97, 0xcf, 0xb6,
0xf1, 0x62, 0x23, 0xbb, 0x4c, 0x1a, 0x93, 0x88, 0x4c, 0xdd, 0xd9, 0xc5,
0xf4, 0x57, 0x57, 0x57, 0xe0, 0xd1, 0xf6, 0x8c, 0x51, 0xde, 0x79, 0x36,
0xd8, 0xae, 0x86, 0xe7, 0x9a, 0x66, 0xe2, 0xec, 0xe3, 0xf9, 0xa0, 0x71,
0xe3, 0xe7, 0xdb, 0xf8, 0x31, 0x11, 0x5d, 0xc5, 0xa7, 0xee, 0xa4, 0x76,
0xe5, 0xf9, 0xf9, 0xf9, 0x95, 0x60, 0xe0, 0xb1, 0x89, 0xe8, 0xff, 0xff,
0xff, 0x7f, 0x3e, 0xda, 0x88, 0x88, 0x88, 0x57, 0x1f, 0xa5, 0x41, 0x17,
0x7c, 0x24, 0x0d, 0x44, 0x5d, 0x21, 0xb0, 0x8f, 0x56, 0xdf, 0xc9, 0xad,
0xef, 0x91, 0x5a, 0xdf, 0x08, 0x08, 0x08, 0x9c, 0x6a, 0xe2, 0x3c, 0x15,
0x72, 0x9f, 0x6e, 0xe3, 0x7d, 0x3c, 0xd9, 0x64, 0x24, 0xbe, 0xcd, 0xb4,
0xf0, 0x83, 0x42, 0xdb, 0x81, 0x40, 0xdb, 0xb3, 0x8d, 0xe9, 0x7a, 0x36,
0xd9, 0x99, 0x66, 0xe1, 0x87, 0x4a, 0xdc, 0x38, 0x14, 0x6b, 0x2e, 0x10,
0x58, 0x2d, 0x16, 0x4b, 0x46, 0x19, 0x86, 0xd8, 0xc5, 0xf3, 0x6e, 0x27,
0xd1, 0xd3, 0xbb, 0xf3, 0x52, 0x52, 0x52, 0x78, 0x34, 0xd8, 0xd5, 0xc1,
0xf3, 0x97, 0x60, 0xe1, 0x94, 0x5e, 0xe0, 0x8f, 0x54, 0xdf, 0x51, 0x1d,
0x99, 0x7c, 0x7c, 0x7c, 0x06, 0x06, 0x06, 0xee, 0xe5, 0xfa, 0xa6, 0x79,
0xe5, 0x93, 0x5a, 0xdf, 0x5b, 0x20, 0xad, 0xad, 0x81, 0xe7, 0xeb, 0xe1,
0xf9, 0xe9, 0xdd, 0xf9, 0xc9, 0xaf, 0xef, 0x48, 0x1a, 0x8b, 0xd9, 0xc7,
0xf5, 0x8b, 0x50, 0xdd, 0x83, 0x44, 0xdb, 0x8d, 0x52, 0xdf, 0xc1, 0xa3,
0xed, 0xcf, 0xb7, 0xf1, 0xc3, 0xa5, 0xed, 0xa3, 0x74, 0xe4, 0xbd, 0x9d,
0xed, 0xc5, 0xa9, 0xef, 0xd1, 0xbb, 0xf3, 0xcd, 0xb5, 0xf1, 0xb7, 0x93,
0xea, 0x54, 0x1e, 0x9f, 0xa9, 0x7e, 0xe6, 0x97, 0x62, 0xe1, 0x93, 0x5c,
0xdf, 0xad, 0x83, 0xe7, 0xda, 0xf7, 0xd7, 0x2d, 0x00, 0x00, 0x00, 0x09,
0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x12, 0x00, 0x00, 0x0b, 0x12,
0x01, 0xd2, 0xdd, 0x7e, 0xfc, 0x00, 0x00, 0x00, 0x1c, 0x74, 0x45, 0x58,
0x74, 0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x00, 0x41, 0x64,
0x6f, 0x62, 0x65, 0x20, 0x46, 0x69, 0x72, 0x65, 0x77, 0x6f, 0x72, 0x6b,
0x73, 0x20, 0x43, 0x53, 0x35, 0x71, 0xb5, 0xe3, 0x36, 0x00, 0x00, 0x02,
0x0b, 0x49, 0x44, 0x41, 0x54, 0x38, 0x8d, 0x85, 0xd3, 0xfb, 0x4f, 0xd3,
0x50, 0x14, 0x07, 0xf0, 0x23, 0xb4, 0x13, 0x65, 0x58, 0xc0, 0xe1, 0x3a,
0x51, 0x44, 0x37, 0x5f, 0xc0, 0xec, 0x5c, 0x9d, 0x6e, 0xe2, 0xa6, 0x74,
0x6e, 0x85, 0x5a, 0x20, 0xad, 0x52, 0xe6, 0x74, 0x53, 0x53, 0x5f, 0x0c,
0x4b, 0x11, 0x63, 0xba, 0xa9, 0xdb, 0x30, 0x21, 0xbe, 0x42, 0x4c, 0x8c,
0x26, 0xb2, 0x1f, 0x7c, 0xff, 0xa3, 0xde, 0xdb, 0xae, 0xdd, 0xd8, 0x86,
0x9e, 0xdf, 0x4e, 0xbf, 0x9f, 0x9c, 0x9b, 0x9c, 0x7b, 0x0b, 0xa1, 0xff,
0x14, 0x6c, 0x6f, 0x13, 0xff, 0x06, 0xe4, 0xf1, 0x0b, 0x7b, 0xcf, 0x90,
0x3b, 0x83, 0xa9, 0xb1, 0xcb, 0xfc, 0xcf, 0xc7, 0x33, 0x07, 0xce, 0xee,
0x00, 0x46, 0x5e, 0x2e, 0xde, 0xba, 0x21, 0x57, 0x77, 0x29, 0x2f, 0xd6,
0x9b, 0xc6, 0x38, 0x20, 0xd1, 0x7d, 0x9e, 0xff, 0xb8, 0xef, 0x1c, 0x3f,
0x57, 0xc8, 0x4d, 0x2f, 0xef, 0x9f, 0x69, 0x07, 0xfd, 0xc9, 0x9b, 0xef,
0xd1, 0x80, 0xf1, 0xc1, 0xc9, 0x2d, 0x31, 0x5c, 0x83, 0x76, 0x00, 0xcf,
0xe5, 0x4b, 0xd6, 0x00, 0x31, 0xec, 0x53, 0x3a, 0x01, 0xb6, 0xa8, 0x1d,
0xe5, 0xf1, 0x80, 0xb0, 0x4b, 0xe9, 0x08, 0x68, 0xb6, 0xf8, 0x8c, 0x1d,
0x10, 0x73, 0xe1, 0xdf, 0x8a, 0xb2, 0xda, 0x09, 0x2c, 0x61, 0xe1, 0x8d,
0xc6, 0xe9, 0x8a, 0xb2, 0xca, 0xb4, 0x81, 0x44, 0x08, 0x92, 0x75, 0x51,
0x41, 0x03, 0x84, 0x16, 0x40, 0xbe, 0x7d, 0xb7, 0x0e, 0x1b, 0x75, 0x81,
0x73, 0x09, 0xc8, 0x66, 0x30, 0x35, 0xd6, 0xb5, 0x15, 0x87, 0xbb, 0x48,
0x2c, 0x20, 0x81, 0x0e, 0x70, 0xb3, 0xe0, 0xec, 0x13, 0x81, 0x91, 0x13,
0xbe, 0x72, 0xb9, 0x0a, 0xbf, 0x2c, 0xe1, 0x46, 0xb9, 0x34, 0x3f, 0xa4,
0x3c, 0x38, 0x68, 0xed, 0x13, 0x12, 0xdd, 0x6f, 0x44, 0x59, 0x96, 0x7b,
0x28, 0x8a, 0xb1, 0x04, 0x23, 0x48, 0xf3, 0x2b, 0xc2, 0x67, 0x57, 0x4e,
0xdf, 0xc4, 0xfb, 0x84, 0x7e, 0x2f, 0x2f, 0xe3, 0xe2, 0xf3, 0x11, 0x4a,
0xc5, 0x42, 0x90, 0x02, 0x2b, 0x12, 0x9d, 0x5d, 0xe3, 0xbe, 0x66, 0xf0,
0xf9, 0x00, 0x03, 0x93, 0x65, 0x53, 0xf4, 0xac, 0xc5, 0x2f, 0x46, 0xd4,
0xe4, 0x92, 0x3b, 0x10, 0x64, 0x97, 0xaf, 0xce, 0x71, 0xdf, 0x68, 0xc2,
0x02, 0x86, 0x51, 0x13, 0xcd, 0x21, 0xe3, 0xd2, 0xd0, 0x23, 0x88, 0x44,
0x03, 0x41, 0x7a, 0xe3, 0x1e, 0xc7, 0x0d, 0x7e, 0x21, 0x1c, 0x60, 0x18,
0xda, 0x77, 0x4e, 0xae, 0x32, 0xd4, 0xab, 0xdd, 0xf0, 0x34, 0x76, 0xec,
0x35, 0x93, 0x2d, 0x70, 0x85, 0x51, 0xc2, 0x06, 0x71, 0x2c, 0x8c, 0x4c,
0x6a, 0x94, 0xa2, 0xa8, 0xdb, 0xa0, 0x7a, 0xa3, 0x0b, 0x9a, 0xee, 0x4b,
0x55, 0x08, 0x07, 0xe8, 0x19, 0x53, 0x18, 0x28, 0xa7, 0x82, 0xa0, 0xaa,
0x2e, 0x1d, 0x17, 0xd1, 0x00, 0x1f, 0x7c, 0x19, 0x07, 0x7c, 0x42, 0x40,
0x6f, 0x02, 0x77, 0x30, 0x48, 0xe5, 0x2d, 0x81, 0x01, 0xd5, 0x02, 0x7a,
0xf7, 0x20, 0x30, 0xbd, 0x98, 0xd7, 0x6c, 0x50, 0xda, 0x06, 0x62, 0x7d,
0xe9, 0xf4, 0x15, 0xf0, 0x07, 0xb2, 0x7f, 0x6a, 0x9a, 0x05, 0x4a, 0x13,
0x4f, 0x1e, 0x76, 0x39, 0x20, 0xd6, 0x77, 0x24, 0xdd, 0x7b, 0x08, 0x48,
0x8f, 0x7f, 0xf3, 0xd4, 0x49, 0x0d, 0x83, 0xd2, 0xc4, 0xe1, 0xfb, 0xd7,
0x87, 0x67, 0x8b, 0x16, 0xb0, 0x72, 0x7c, 0x59, 0x88, 0xfc, 0x60, 0xe3,
0x06, 0xce, 0xd1, 0x17, 0xd2, 0x63, 0x12, 0x3b, 0xaf, 0xbf, 0x07, 0x8f,
0x7f, 0x56, 0xb0, 0x72, 0xb3, 0x43, 0xc4, 0xce, 0xed, 0x17, 0x85, 0x88,
0x9d, 0xe3, 0xee, 0xda, 0xb0, 0x9d, 0x37, 0xde, 0x24, 0x79, 0x3a, 0xd4,
0x54, 0x8d, 0xae, 0xe5, 0xef, 0x6e, 0xaf, 0xbf, 0x82, 0x92, 0xe7, 0x5e,
0x38, 0x90, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44,
0xae, 0x42, 0x60, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
};
unsigned int kSampleTarLength = 10240;