switch (event->type())
        {
        case QEvent::GraphicsSceneMouseDoubleClick:
            consumeEvent = true;
            // Need to queue this since if we change out display in the middle of processing input
            // Things get sad.
            QTimer::singleShot(0, [this]() { this->SetEditable(true); });
            break;
        }

/*
* its licensors.
*
*
*/
#include "precompiled.h"

#include <functional>

AZ_PUSH_DISABLE_WARNING(4251 4800 4244, "-Wunknown-warning-option")
#include <QEvent>
#include <QGraphicsItem>
#include <QGraphicsGridLayout>
#include <QGraphicsLayoutItem>
#include <QGraphicsScene>
#include <qgraphicssceneevent.h>
#include <QGraphicsWidget>
#include <QPainter>
AZ_POP_DISABLE_WARNING

#include <Components/Nodes/Comment/CommentTextGraphicsWidget.h>

#include <GraphCanvas/Components/GeometryBus.h>
#include <GraphCanvas/Components/Nodes/NodeBus.h>
#include <GraphCanvas/Components/Nodes/NodeUIBus.h>
#include <GraphCanvas/Components/Slots/SlotBus.h>
#include <GraphCanvas/Components/VisualBus.h>
#include <GraphCanvas/tools.h>

namespace GraphCanvas
{
    // CommentNodeTextGraphicsWidget
    CommentTextGraphicsWidget::CommentTextGraphicsWidget(const AZ::EntityId& targetId)
        : m_commentMode(CommentMode::Unknown)
        , m_editable(false)
        , m_layoutLock(false)
        , m_displayLabel(nullptr)
        , m_textEdit(nullptr)
        , m_proxyWidget(nullptr)
        , m_pressed(false)
        , m_entityId(targetId)
    {
        setFlag(ItemIsMovable, false);

        m_displayLabel = aznew GraphCanvasLabel();
        m_displayLabel->SetAllowNewlines(true);
        m_layout = new QGraphicsLinearLayout(Qt::Vertical);
        m_layout->setSpacing(0);
        m_layout->setContentsMargins(0, 0, 0, 0);
        m_layout->setInstantInvalidatePropagation(true);

        m_layout->addItem(m_displayLabel);

        setLayout(m_layout);
        setData(GraphicsItemName, QStringLiteral("Comment/%1").arg(static_cast<AZ::u64>(GetEntityId()), 16, 16, QChar('0')));

        SetCommentMode(CommentMode::Comment);
    }

    void CommentTextGraphicsWidget::Activate()
    {
        CommentUIRequestBus::Handler::BusConnect(GetEntityId());
        CommentLayoutRequestBus::Handler::BusConnect(GetEntityId());
        StyleNotificationBus::Handler::BusConnect(GetEntityId());

        UpdateLayout();
    }

    void CommentTextGraphicsWidget::Deactivate()
    {
        StyleNotificationBus::Handler::BusDisconnect();
        CommentLayoutRequestBus::Handler::BusDisconnect();
        CommentUIRequestBus::Handler::BusDisconnect();
    }

    void CommentTextGraphicsWidget::OnAddedToScene()
    {
        UpdateSizing();
    }

    void CommentTextGraphicsWidget::SetStyle(const AZStd::string& style)
    {
        if (m_style != style)
        {
            m_style = style;
            OnStyleChanged();
        }
    }

    void CommentTextGraphicsWidget::UpdateLayout()
    {
        if (m_layoutLock)
        {
            return;
        }

        QGraphicsScene* graphicsScene = nullptr;
        AZ::EntityId sceneId;
        SceneMemberRequestBus::EventResult(sceneId, GetEntityId(), &SceneMemberRequests::GetScene);

        SceneRequestBus::EventResult(graphicsScene, sceneId, &SceneRequests::AsQGraphicsScene);

        prepareGeometryChange();

        for (int i = m_layout->count() - 1; i >= 0; --i)
        {
            QGraphicsLayoutItem* layoutItem = m_layout->itemAt(i);
            m_layout->removeAt(i);
            layoutItem->setParentLayoutItem(nullptr);

            if (graphicsScene)
            {
                graphicsScene->removeItem(layoutItem->graphicsItem());
            }
        }

        if (m_editable)
        {
            // Adjust the size of the editable widget to match the label
            m_layout->addItem(m_proxyWidget);
            UpdateSizing();
        }
        else
        {
            m_layout->addItem(m_displayLabel);
        }

        RefreshDisplay();
    }

    void CommentTextGraphicsWidget::UpdateStyles()
    {
        Styling::StyleHelper overallStyle(GetEntityId());
        qreal margin = overallStyle.GetAttribute(Styling::Attribute::Margin, 0.0);

        m_layout->setContentsMargins(margin, margin, margin, margin);

        m_displayLabel->SetStyle(GetEntityId(), m_style.c_str());

        const Styling::StyleHelper& styleHelper = m_displayLabel->GetStyleHelper();

        QPen border = styleHelper.GetBorder();

        // We construct a stylesheet for the Qt widget based on our calculated style
        QStringList fields;

        fields.push_back("background-color: rgba(0,0,0,0)");

        fields.push_back(QString("border-width: %1").arg(border.width()));

        switch (border.style())
        {
        case Qt::PenStyle::SolidLine:
            fields.push_back("border-style: solid");
            break;
        case Qt::PenStyle::DashLine:
            fields.push_back("border-style: dashed");
            break;
        case Qt::PenStyle::DotLine:
            fields.push_back("border-style: dotted");
            break;
        default:
            fields.push_back("border-style: none");
        }

        fields.push_back(QString("border-color: rgba(%1,%2,%3,%4)").arg(border.color().red()).arg(border.color().green()).arg(border.color().blue()).arg(border.color().alpha()));
        fields.push_back(QString("border-radius: %1").arg(styleHelper.GetAttribute(Styling::Attribute::BorderRadius, 0)));

        fields.push_back("margin: 0");
        fields.push_back("padding: 0");

        fields.push_back(styleHelper.GetFontStyleSheet());

        if (m_textEdit)
        {
            m_textEdit->setStyleSheet(fields.join("; ").toUtf8().data());

            if (styleHelper.HasTextAlignment())
            {
                m_textEdit->setAlignment(styleHelper.GetTextAlignment(m_textEdit->alignment()));
            }
        }

        UpdateSizing();
    }

    void CommentTextGraphicsWidget::RefreshDisplay()
    {
        updateGeometry();
        m_layout->invalidate();
        update();
    }

    void CommentTextGraphicsWidget::SetComment(const AZStd::string& comment)
    {
        m_commentText = comment;
        if (!comment.empty())
        {
            m_displayLabel->SetLabel(comment);
            if (m_textEdit)
            {
                m_textEdit->setPlainText(comment.c_str());
            }
        }
        else
        {
            // Hack to force the minimum height based on the style's font/size
            m_displayLabel->SetLabel(" ");
            if (m_textEdit)
            {
                m_textEdit->setPlainText(" ");
            }
        }

        UpdateSizing();
    }

    AZStd::string CommentTextGraphicsWidget::GetComment() const
    {
        return m_commentText;
    }

    Styling::StyleHelper& CommentTextGraphicsWidget::GetStyleHelper()
    {
        return m_displayLabel->GetStyleHelper();
    }

    const Styling::StyleHelper& CommentTextGraphicsWidget::GetStyleHelper() const
    {
        return m_displayLabel->GetStyleHelper();
    }

    void CommentTextGraphicsWidget::SetCommentMode(CommentMode commentMode)
    {
        if (m_commentMode != commentMode)
        {
            m_commentMode = commentMode;
            UpdateSizePolicies();
        }
    }

    CommentMode CommentTextGraphicsWidget::GetCommentMode() const
    {
        return m_commentMode;
    }

    void CommentTextGraphicsWidget::SetEditable(bool editable)
    {
        if (m_editable != editable)
        {
            m_editable = editable;

            if (!m_editable)
            {
                SubmitValue();
            }

            (m_editable ? SetupProxyWidget() : CleanupProxyWidget());
            UpdateLayout();

            if (m_editable)
            {
                AZ::EntityId sceneId;
                SceneMemberRequestBus::EventResult(sceneId, GetEntityId(), &SceneMemberRequests::GetScene);
                SceneNotificationBus::Event(sceneId, &SceneNotifications::OnNodeIsBeingEdited, true);

                CommentNotificationBus::Event(GetEntityId(), &CommentNotifications::OnEditBegin);
                UpdateSizing();

                StyledEntityRequestBus::Event(GetEntityId(), &StyledEntityRequests::AddSelectorState, Styling::States::Editing);

                m_textEdit->selectAll();

                SceneMemberUIRequestBus::Event(GetEntityId(), &SceneMemberUIRequests::SetSelected, true);
            }
            else
            {
                AZ::EntityId sceneId;
                SceneMemberRequestBus::EventResult(sceneId, GetEntityId(), &SceneMemberRequests::GetScene);
                SceneNotificationBus::Event(sceneId, &SceneNotifications::OnNodeIsBeingEdited, false);

                CommentNotificationBus::Event(GetEntityId(), &CommentNotifications::OnEditEnd);
                StyledEntityRequestBus::Event(GetEntityId(), &StyledEntityRequests::RemoveSelectorState, Styling::States::Editing);
                m_layoutLock = false;
            }

            OnStyleChanged();
        }
    }

    QGraphicsLayoutItem* CommentTextGraphicsWidget::GetGraphicsLayoutItem()
    {
        return this;
    }

    void CommentTextGraphicsWidget::OnStyleChanged()
    {
        UpdateStyles();
        RefreshDisplay();
    }

    void CommentTextGraphicsWidget::UpdateSizing()
    {
        AZStd::string value = (m_textEdit ? AZStd::string(m_textEdit->toPlainText().toUtf8().data()) : m_commentText);
        m_displayLabel->SetLabel(value);

        prepareGeometryChange();

        if (m_textEdit)
        {
            QSizeF oldSize = m_textEdit->minimumSize();

            // As we update the label with the new contents, adjust the editable widget size to match
            if (m_commentMode == CommentMode::Comment)
            {
                m_textEdit->setMinimumSize(m_displayLabel->preferredSize().toSize());
                m_textEdit->setMaximumSize(m_displayLabel->preferredSize().toSize());
            }
            else if (m_commentMode == CommentMode::BlockComment)
            {
                QSizeF preferredSize = m_displayLabel->preferredSize();
                QRectF displaySize = m_displayLabel->GetDisplayedSize();

                displaySize.setHeight(preferredSize.height());

                if (displaySize.width() == 0)
                {
                    m_textEdit->setMinimumHeight(aznumeric_cast<int>(preferredSize.height()));
                    m_textEdit->setMaximumHeight(aznumeric_cast<int>(preferredSize.height()));
                }
                else
                {
                    m_textEdit->setMinimumSize(displaySize.size().toSize());
                    m_textEdit->setMaximumSize(displaySize.size().toSize());
                }
            }

            QSizeF newSize = m_textEdit->minimumSize();

            if (oldSize != newSize)
            {
                CommentNotificationBus::Event(GetEntityId(), &CommentNotifications::OnCommentSizeChanged, oldSize, newSize);
            }
        }

        updateGeometry();
    }

    void CommentTextGraphicsWidget::SubmitValue()
    {
        if (m_textEdit)
        {
            m_commentText = m_textEdit->toPlainText().toUtf8().data();
        }

        CommentRequestBus::Event(GetEntityId(), &CommentRequests::SetComment, m_commentText);
        CommentNotificationBus::Event(GetEntityId(), &CommentNotifications::OnCommentChanged, m_commentText);
        UpdateSizing();
    }

    bool CommentTextGraphicsWidget::sceneEventFilter(QGraphicsItem*, QEvent* event)
    {
        bool consumeEvent = event->isAccepted();

        return consumeEvent;
    }

    void CommentTextGraphicsWidget::UpdateSizePolicies()
    {
        prepareGeometryChange();

        switch (m_commentMode)
        {
        case CommentMode::BlockComment:
            if (m_textEdit)
            {
                m_textEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
                m_textEdit->setWordWrapMode(QTextOption::WrapMode::NoWrap);
                m_proxyWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
            }

            setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
            m_layout->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
            m_displayLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);

            m_displayLabel->SetElide(true);
            m_displayLabel->SetWrap(false);
            m_displayLabel->SetWrapMode(GraphCanvasLabel::WrapMode::BoundingWidth);

            break;
        case CommentMode::Comment:
            if (m_textEdit)
            {
                m_textEdit->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
                m_textEdit->setWordWrapMode(QTextOption::WrapMode::WordWrap);
                m_proxyWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
            }

            setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
            m_layout->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
            m_displayLabel->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);

            m_displayLabel->SetElide(false);
            m_displayLabel->SetWrap(true);
            m_displayLabel->SetWrapMode(GraphCanvasLabel::WrapMode::MaximumWidth);
            break;
        default:
            AZ_Warning("Graph Canvas", false, "Unhandled Comment Mode: %i", m_commentMode);
        }

        updateGeometry();
    }

    void CommentTextGraphicsWidget::SetupProxyWidget()
    {
        if (!m_textEdit)
        {
            m_proxyWidget = new QGraphicsProxyWidget();
            m_proxyWidget->setFocusPolicy(Qt::FocusPolicy::StrongFocus);

            m_textEdit = aznew Internal::FocusableTextEdit();
            m_textEdit->setProperty("HasNoWindowDecorations", true);
            m_textEdit->setProperty("DisableFocusWindowFix", true);
            m_textEdit->setFocusPolicy(Qt::FocusPolicy::StrongFocus);

            m_textEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff);
            m_textEdit->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff);
            m_textEdit->setSizeAdjustPolicy(QAbstractScrollArea::SizeAdjustPolicy::AdjustToContents);
            m_textEdit->setEnabled(true);

            m_proxyWidget->setWidget(m_textEdit);

            UpdateSizePolicies();

            m_textEdit->setPlainText(m_commentText.c_str());

            QTimer::singleShot(0, [&]()
            {
                m_textEdit->setFocus(Qt::FocusReason::MouseFocusReason);
                m_proxyWidget->setFocus(Qt::FocusReason::MouseFocusReason);
            });

            QObject::connect(m_textEdit, &Internal::FocusableTextEdit::textChanged, [this]() { this->UpdateSizing(); });
            QObject::connect(m_textEdit, &Internal::FocusableTextEdit::OnFocusIn, [this]() { this->m_layoutLock = true; });
            QObject::connect(m_textEdit, &Internal::FocusableTextEdit::OnFocusOut, [this]() { this->SubmitValue(); this->m_layoutLock = false; this->SetEditable(false); });
            QObject::connect(m_textEdit, &Internal::FocusableTextEdit::EnterPressed, [this]()
            {
                QTimer::singleShot(0, [this]()
                {
                    this->SubmitValue();
                    this->m_layoutLock = false;
                    this->SetEditable(false);
                });
            });
        }
    }

    void CommentTextGraphicsWidget::CleanupProxyWidget()
    {
        if (m_textEdit)
        {
            delete m_textEdit; // NB: this implicitly deletes m_proxy widget
            m_textEdit = nullptr;
            m_proxyWidget = nullptr;
        }
    }

#include <Source/Components/Nodes/Comment/CommentTextGraphicsWidget.moc>
}


int32 FAutoPackageBackup::GetMaxAllowedBackupSpace()
{
	int32 MaxSpaceAllowed = 0;
	if ( GConfig->GetInt( TEXT("FAutoPackageBackup"), TEXT("MaxAllowedSpaceInMB"), MaxSpaceAllowed, GEditorPerProjectIni ) )
	{
		// Convert the user stored value from megabytes to bytes; <<= 20 is the same as *= 1024 * 1024
		MaxSpaceAllowed <<= 20;
	}
	return MaxSpaceAllowed;
}

/*=============================================================================
	PackageBackup.cpp: Utility class for backing up a package.
=============================================================================*/

#include "PackageBackup.h"
#include "HAL/FileManager.h"
#include "Misc/Paths.h"
#include "Misc/ConfigCacheIni.h"
#include "Misc/FeedbackContext.h"
#include "UObject/Package.h"
#include "Misc/PackageName.h"

/**
 * Helper struct to hold information on backup files to prevent redundant checks
 */
struct FBackupFileInfo
{
	int32 FileSize;						/** Size of the file */
	FString FileName;					/** Name of the file */
	FDateTime FileTimeStamp;			/** Timestamp of the file */
};

/**
 * Create a backup of the specified package. A backup is only created if the specified
 * package meets specific criteria, as outlined in the comments for ShouldBackupPackage().
 *
 * @param	InPackage	Package which should be backed up
 *
 * @see		FAutoPackageBackup::ShouldBackupPackage()
 *
 * @return	true if the package was successfully backed up; false if it was not
 */
bool FAutoPackageBackup::BackupPackage( const UPackage& InPackage )
{
	bool bPackageBackedUp = false;
	FString OriginalFileName;

	// Check if the package is valid for being backed up
	if ( ShouldBackupPackage( InPackage, OriginalFileName ) )
	{
		GWarn->StatusUpdate( -1, -1, NSLOCTEXT("UnrealEd", "PackageBackup_Warning", "Backing up asset...") );

		// Construct the backup file name by appending a timestamp in between the base file name and extension
		FString DestinationFileName = GetBackupDirectory() / FPaths::GetBaseFilename(OriginalFileName);

		DestinationFileName += TEXT("_");
		DestinationFileName += FDateTime::Now().ToString(TEXT("%Y-%m-%d-%H-%M-%S"));
		DestinationFileName += FPaths::GetExtension( OriginalFileName, true );

		// Copy the file to the backup file name
		IFileManager::Get().Copy( *DestinationFileName, *OriginalFileName );

		bPackageBackedUp = true;
	}

	return bPackageBackedUp;
}

/**
 * Create a backup of the specified packages. A backup is only created if a specified
 * package meets specific criteria, as outlined in the comments for ShouldBackupPackage().
 *
 * @param	InPackage	Package which should be backed up
 *
 * @see		FAutoPackageBackup::ShouldBackupPackage()
 *
 * @return	true if all provided packages were successfully backed up; false if one or more
 *			were not
 */
bool FAutoPackageBackup::BackupPackages( const TArray<UPackage*>& InPackages )
{
	bool bAllPackagesBackedUp = true;
	for ( TArray<UPackage*>::TConstIterator PackageIter( InPackages ); PackageIter; ++PackageIter )
	{
		UPackage* CurPackage = *PackageIter;
		check( CurPackage );

		if ( !BackupPackage( *CurPackage ) )
		{
			bAllPackagesBackedUp = false;
		}
	}
	return bAllPackagesBackedUp;
}

/**
 * Helper function designed to determine if the provided package should be backed up or not.
 * The function checks for many conditions, such as if the package is too large to backup,
 * if the package has a particular attribute that should prevent it from being backed up (such
 * as being marked for PIE-use), if cooking is in progress, etc.
 *
 * @param	InPackage		Package which should be checked to see if its valid for backing-up
 * @param	OutFileName		File name of the package on disk if the function determines the package
 *							already existed
 *
 * @return	true if the package is valid for backing-up; false otherwise
 */
bool FAutoPackageBackup::ShouldBackupPackage( const UPackage& InPackage, FString& OutFilename )
{
	// Check various conditions to see if the package is a valid candidate for backing up
	bool bShouldBackup =
		GIsEditor																			// Backing up packages only makes sense in the editor
		&& !IsRunningCommandlet()															// Don't backup saves resulting from commandlets
		&& IsPackageBackupEnabled()															// Ensure that the package backup is enabled in the first place
		&& (InPackage.HasAnyPackageFlags(PKG_PlayInEditor) == false)						// Don't back up PIE packages
		&& (InPackage.HasAnyPackageFlags(PKG_ContainsScript) == false);						// Don't back up script packages

	if (!bShouldBackup)
	{
		// Early out here to avoid the call to FileSize below which can be expensive on slower hard drives
		return false;
	}

	if( bShouldBackup )
	{
		GWarn->StatusUpdate( -1, -1, NSLOCTEXT("UnrealEd", "PackageBackup_ValidityWarning", "Determining asset backup validity...") );

		bShouldBackup =	FPackageName::DoesPackageExist( InPackage.GetName(), NULL, &OutFilename );	// Make sure the file already exists (no sense in backing up a new package)
	}

	// If the package passed the initial backup checks, proceed to check more specific conditions
	// that might disqualify the package from being backed up
	const int32 FileSizeOfBackup = IFileManager::Get().FileSize( *OutFilename );
	if ( bShouldBackup )
	{
		// Ensure that the size the backup would require is less than that of the maximum allowed
		// space for backups
		bShouldBackup = FileSizeOfBackup <= GetMaxAllowedBackupSpace();
	}

	// If all of the prior checks have passed, now see if the package has been backed up
	// too recently to be considered for an additional backup
	if ( bShouldBackup )
	{
		// Ensure that the autosave/backup directory exists
		const FString& BackupSaveDir = GetBackupDirectory();
		IFileManager::Get().MakeDirectory( *BackupSaveDir, 1 );

		// Find all of the files in the backup directory
		TArray<FString> FilesInBackupDir;
		IFileManager::Get().FindFilesRecursive(FilesInBackupDir, *BackupSaveDir, TEXT("*.*"), true, false);

		// Extract the base file name and extension from the passed-in package file name
		FString ExistingBaseFileName = FPaths::GetBaseFilename(OutFilename);
		FString ExistingFileNameExtension = FPaths::GetExtension(OutFilename);

		bool bFoundExistingBackup = false;
		int32 DirectorySize = 0;
		FDateTime LastBackupTimeStamp = FDateTime::MinValue();

		TArray<FBackupFileInfo> BackupFileInfoArray;

		// Check every file in the backup directory for matches against the passed-in package
		// (Additionally keep statistics on all backup files for potential maintenance)
		for ( TArray<FString>::TConstIterator FileIter( FilesInBackupDir ); FileIter; ++FileIter )
		{
			const FString CurBackupFileName = FString( *FileIter );

			// Create a new backup file info struct for keeping information about each backup file
			const int32 FileInfoIndex = BackupFileInfoArray.AddZeroed();
			FBackupFileInfo& CurBackupFileInfo = BackupFileInfoArray[ FileInfoIndex ];

			// Record the backup file's name, size, and timestamp
			CurBackupFileInfo.FileName = CurBackupFileName;
			CurBackupFileInfo.FileSize = IFileManager::Get().FileSize( *CurBackupFileName );

			// If we failed to get a timestamp or a valid size, something has happened to the file and it shouldn't be considered
			CurBackupFileInfo.FileTimeStamp = IFileManager::Get().GetTimeStamp(*CurBackupFileName);
			if (CurBackupFileInfo.FileTimeStamp == FDateTime::MinValue() || CurBackupFileInfo.FileSize == -1)
			{
				BackupFileInfoArray.RemoveAt( BackupFileInfoArray.Num() - 1 );
				continue;
			}

			// Calculate total directory size by adding the size of this backup file
			DirectorySize += CurBackupFileInfo.FileSize;

			FString CurBackupBaseFileName =  FPaths::GetBaseFilename(CurBackupFileName);
			FString CurBackupFileNameExtension = FPaths::GetExtension(CurBackupFileName);

			// The base file name of the backup file is going to include an underscore followed by a timestamp, so they must be removed for comparison's sake
			CurBackupBaseFileName = CurBackupBaseFileName.Left( CurBackupBaseFileName.Find( TEXT("_"), ESearchCase::CaseSensitive, ESearchDir::FromEnd ) );

			// If the base file names and extensions match, we've found a backup
			if ( CurBackupBaseFileName == ExistingBaseFileName &&  CurBackupFileNameExtension == ExistingFileNameExtension )
			{
				bFoundExistingBackup = true;

				// Keep track of the most recent matching time stamp so we can check if the passed-in package
				// has been backed up too recently
				if ( CurBackupFileInfo.FileTimeStamp > LastBackupTimeStamp )
				{
					LastBackupTimeStamp = CurBackupFileInfo.FileTimeStamp;
				}
			}
		}

		// If there was an existing backup, check to see if it was created too recently to allow another backup
		if ( bFoundExistingBackup )
		{
			// Check the difference in timestamp seconds against the backup interval; if not enough time has elapsed since
			// the last backup, we don't want to make another one
			if ((FDateTime::UtcNow() - LastBackupTimeStamp).GetTotalSeconds() < GetBackupInterval())
			{
				bShouldBackup = false;
			}
		}

		// If every other check against the package has succeeded for backup purposes, ensure there is enough directory space
		// available in the backup directory, as adding the new backup might use more space than the user allowed for backups.
		// If the backup file size + the current directory size exceeds the max allowed space, deleted old backups until there
		// is sufficient space. If enough space can't be freed for whatever reason, then no back-up will be created.
		if ( bShouldBackup && ( FileSizeOfBackup + DirectorySize > GetMaxAllowedBackupSpace() ) )
		{
			bShouldBackup = PerformBackupSpaceMaintenance( BackupFileInfoArray, DirectorySize, FileSizeOfBackup );
		}
	}

	return bShouldBackup;
}

/**
 * Helper function that returns whether the user has package backups enabled or not. The value
 * is determined by a configuration INI setting.
 *
 * @return	true if package backups are enabled; false otherwise
 */
bool FAutoPackageBackup::IsPackageBackupEnabled()
{
	bool bEnabled = false;
	GConfig->GetBool( TEXT("FAutoPackageBackup"), TEXT("Enabled"), bEnabled, GEditorPerProjectIni );
	return bEnabled;
}

/**
 * Helper function that returns the maximum amount of space the user has designated to allow for
 * package backups. This value is determined by a configuration INI setting.
 *
 * @return	The maximum amount of space allowed, in bytes
 */

/**
 * Helper function that returns the time in between backups of a package before another backup of
 * the same package should be considered valid. This value is determined by a configuration INI setting,
 * and prevents a package from being backed-up over and over again in a small time frame.
 *
 * @return	The interval to wait before allowing another backup of the same package, in seconds
 */
int32 FAutoPackageBackup::GetBackupInterval()
{
	int32 BackupInterval = 0;
	if ( GConfig->GetInt( TEXT("FAutoPackageBackup"), TEXT("BackupIntervalInMinutes"), BackupInterval, GEditorPerProjectIni ) )
	{
		// Convert the user stored value from minutes to seconds
		BackupInterval *= 60;
	}
	return BackupInterval;
}

/**
 * Helper function that returns the directory to store package backups in.
 *
 * @return	String containing the directory to store package backups in.
 */
FString FAutoPackageBackup::GetBackupDirectory()
{
	FString Directory = FPaths::ProjectSavedDir() / TEXT("Backup");
	return Directory;
}

/**
 * Deletes old backed-up package files until the provided amount of space (in bytes)
 * is available to use in the backup directory. Fails if the provided amount of space
 * is more than the amount of space the user has allowed for backups or if enough space
 * could not be made.
 *
 * @param	InBackupFiles		File info of the files in the backup directory
 * @param	InSpaceUsed			The amount of space, in bytes, the files in the provided array take up
 * @param	InSpaceRequired		The amount of space, in bytes, to assure is available
 *								for the purposes of package backups
 *
 * @return	true if the space was successfully provided, false if not or if the requested space was
 *			greater than the max allowed space by the user
 */
bool FAutoPackageBackup::PerformBackupSpaceMaintenance( TArray<FBackupFileInfo>& InBackupFiles, int32 InSpaceUsed, int32 InSpaceRequired )
{
	bool bSpaceFreed = false;

	const int32 MaxAllowedSpace = GetMaxAllowedBackupSpace();

	// We can only free up enough space if the required space is less than the maximum allowed space to begin with
	if ( InSpaceRequired < MaxAllowedSpace )
	{
		GWarn->StatusUpdate( -1, -1, NSLOCTEXT("UnrealEd", "PackageBackup_MaintenanceWarning", "Performing maintenance on asset backup folder...") );

		// Sort the backup files in order of their timestamps; we want to naively delete the oldest files first
		struct FCompareFBackupFileInfo
		{
			FORCEINLINE bool operator()( const FBackupFileInfo& A, const FBackupFileInfo& B ) const
			{
				return A.FileTimeStamp < B.FileTimeStamp;
			}
		};
		InBackupFiles.Sort( FCompareFBackupFileInfo() );

		int32 CurSpaceUsed = InSpaceUsed;
		TArray<FBackupFileInfo>::TConstIterator BackupFileIter( InBackupFiles );

		// Iterate through the backup files until all of the files have been deleted or enough space has been freed
		while ( ( InSpaceRequired + CurSpaceUsed > MaxAllowedSpace ) && BackupFileIter )
		{
			const FBackupFileInfo& CurBackupFileInfo = *BackupFileIter;

			// Delete the file; this could potentially fail, but not because of a read-only flag, so if it fails
			// it's likely because the file was removed by the user
			IFileManager::Get().Delete( *CurBackupFileInfo.FileName, true, true );
			CurSpaceUsed -= CurBackupFileInfo.FileSize;
			++BackupFileIter;
		}
		if ( InSpaceRequired + CurSpaceUsed <= MaxAllowedSpace )
		{
			bSpaceFreed = true;
		}
	}

	return bSpaceFreed;
}


/*
===========================================================================

If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.

===========================================================================
*/

#if defined( MACOS_X ) || defined(__unix__)
#include <signal.h>
#include <sys/types.h>
#endif

#ifndef _MSC_VER
#include <unistd.h>
#endif

#include <SDL_endian.h>

#include "sys/platform.h"
#include "idlib/math/Vector.h"
#include "idlib/math/Polynomial.h"
#include "idlib/Str.h"
#include "idlib/Dict.h"
#include "framework/Common.h"

#include "idlib/Lib.h"

/*
===============================================================================

	idLib

===============================================================================
*/

idSys *			idLib::sys			= NULL;
idCommon *		idLib::common		= NULL;
idCVarSystem *	idLib::cvarSystem	= NULL;
idFileSystem *	idLib::fileSystem	= NULL;
int				idLib::frameNumber	= 0;

/*
================
idLib::Init
================
*/
void idLib::Init( void ) {

	assert( sizeof( bool ) == 1 );

	// assumptions from the scripting compiler/interpreter
	assert( sizeof( float ) == sizeof( int ) );
	assert( sizeof( idVec3 ) == sizeof( float ) * 3 );

	// initialize memory manager
	Mem_Init();

	// init string memory allocator
	idStr::InitMemory();

	// initialize generic SIMD implementation
	idSIMD::Init();

	// initialize math
	idMath::Init();

	// test idMatX

	// test idPolynomial
	idPolynomial::Test();

	// initialize the dictionary string pools
	idDict::Init();
}

/*
================
idLib::ShutDown
================
*/
void idLib::ShutDown( void ) {

	// shut down the dictionary string pools
	idDict::Shutdown();

	// shut down the string memory allocator
	idStr::ShutdownMemory();

	// shut down the SIMD engine
	idSIMD::Shutdown();

	// shut down the memory manager
	Mem_Shutdown();
}

/*
===============================================================================

	Colors

===============================================================================
*/

idVec4	colorBlack	= idVec4( 0.00f, 0.00f, 0.00f, 1.00f );
idVec4	colorWhite	= idVec4( 1.00f, 1.00f, 1.00f, 1.00f );
idVec4	colorRed	= idVec4( 1.00f, 0.00f, 0.00f, 1.00f );
idVec4	colorGreen	= idVec4( 0.00f, 1.00f, 0.00f, 1.00f );
idVec4	colorBlue	= idVec4( 0.00f, 0.00f, 1.00f, 1.00f );
idVec4	colorYellow	= idVec4( 1.00f, 1.00f, 0.00f, 1.00f );
idVec4	colorMagenta= idVec4( 1.00f, 0.00f, 1.00f, 1.00f );
idVec4	colorCyan	= idVec4( 0.00f, 1.00f, 1.00f, 1.00f );
idVec4	colorOrange	= idVec4( 1.00f, 0.50f, 0.00f, 1.00f );
idVec4	colorPurple	= idVec4( 0.60f, 0.00f, 0.60f, 1.00f );
idVec4	colorPink	= idVec4( 0.73f, 0.40f, 0.48f, 1.00f );
idVec4	colorBrown	= idVec4( 0.40f, 0.35f, 0.08f, 1.00f );
idVec4	colorLtGrey	= idVec4( 0.75f, 0.75f, 0.75f, 1.00f );
idVec4	colorMdGrey	= idVec4( 0.50f, 0.50f, 0.50f, 1.00f );
idVec4	colorDkGrey	= idVec4( 0.25f, 0.25f, 0.25f, 1.00f );

static dword colorMask[2] = { 255, 0 };

/*
================
ColorFloatToByte
================
*/
ID_INLINE static byte ColorFloatToByte( float c ) {
	return (byte) ( ( (dword) ( c * 255.0f ) ) & colorMask[FLOATSIGNBITSET(c)] );
}

/*
================
PackColor
================
*/
dword PackColor( const idVec4 &color ) {
	dword dw, dx, dy, dz;

	dx = ColorFloatToByte( color.x );
	dy = ColorFloatToByte( color.y );
	dz = ColorFloatToByte( color.z );
	dw = ColorFloatToByte( color.w );

#if SDL_BYTEORDER == SDL_LIL_ENDIAN
	return ( dx << 0 ) | ( dy << 8 ) | ( dz << 16 ) | ( dw << 24 );
#else
	return ( dx << 24 ) | ( dy << 16 ) | ( dz << 8 ) | ( dw << 0 );
#endif
}

/*
================
UnpackColor
================
*/
void UnpackColor( const dword color, idVec4 &unpackedColor ) {
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
	unpackedColor.Set( ( ( color >> 0 ) & 255 ) * ( 1.0f / 255.0f ),
						( ( color >> 8 ) & 255 ) * ( 1.0f / 255.0f ),
						( ( color >> 16 ) & 255 ) * ( 1.0f / 255.0f ),
						( ( color >> 24 ) & 255 ) * ( 1.0f / 255.0f ) );
#else
	unpackedColor.Set( ( ( color >> 24 ) & 255 ) * ( 1.0f / 255.0f ),
						( ( color >> 16 ) & 255 ) * ( 1.0f / 255.0f ),
						( ( color >> 8 ) & 255 ) * ( 1.0f / 255.0f ),
						( ( color >> 0 ) & 255 ) * ( 1.0f / 255.0f ) );
#endif
}

/*
================
PackColor
================
*/
dword PackColor( const idVec3 &color ) {
	dword dx, dy, dz;

	dx = ColorFloatToByte( color.x );
	dy = ColorFloatToByte( color.y );
	dz = ColorFloatToByte( color.z );

#if SDL_BYTEORDER == SDL_LIL_ENDIAN
	return ( dx << 0 ) | ( dy << 8 ) | ( dz << 16 );
#else
	return ( dy << 16 ) | ( dz << 8 ) | ( dx << 0 );
#endif
}

/*
================
UnpackColor
================
*/

/*
===============
idLib::Error
===============
*/
void idLib::Error( const char *fmt, ... ) {
	va_list		argptr;
	char		text[MAX_STRING_CHARS];

	va_start( argptr, fmt );
	idStr::vsnPrintf( text, sizeof( text ), fmt, argptr );
	va_end( argptr );

	common->Error( "%s", text );
}

/*
===============
idLib::Warning
===============
*/
void idLib::Warning( const char *fmt, ... ) {
	va_list		argptr;
	char		text[MAX_STRING_CHARS];

	va_start( argptr, fmt );
	idStr::vsnPrintf( text, sizeof( text ), fmt, argptr );
	va_end( argptr );

	common->Warning( "%s", text );
}

/*
===============================================================================

	Byte order functions

===============================================================================
*/

/*
================
FloatSwap
================
*/
ID_INLINE static float FloatSwap( float f ) {
	union {
		float	f;
		unsigned int u;
	} id_attribute((may_alias)) dat;

	dat.f = f;
	dat.u = SDL_Swap32(dat.u);

	return dat.f;
}

/*
=====================================================================
RevBytesSwap

Reverses byte order in place.

INPUTS
   bp       bytes to reverse
   elsize   size of the underlying data type
   elcount  number of elements to swap

RESULTS
   Reverses the byte order in each of elcount elements.
===================================================================== */
ID_INLINE static void RevBytesSwap( void *bp, int elsize, int elcount ) {
	register unsigned char *p, *q;

	p = ( unsigned char * ) bp;

	if ( elsize == 2 ) {
		q = p + 1;
		while ( elcount-- ) {
			*p ^= *q;
			*q ^= *p;
			*p ^= *q;
			p += 2;
			q += 2;
		}
		return;
	}

	while ( elcount-- ) {
		q = p + elsize - 1;
		while ( p < q ) {
			*p ^= *q;
			*q ^= *p;
			*p ^= *q;
			++p;
			--q;
		}
		p += elsize >> 1;
	}
}

/*
 =====================================================================
 RevBytesSwap

 Reverses byte order in place, then reverses bits in those bytes

 INPUTS
 bp       bitfield structure to reverse
 elsize   size of the underlying data type

 RESULTS
 Reverses the bitfield of size elsize.
 ===================================================================== */
ID_INLINE static void RevBitFieldSwap( void *bp, int elsize) {
	int i;
	unsigned char *p, t, v;

	LittleRevBytes( bp, elsize, 1 );

	p = (unsigned char *) bp;
	while ( elsize-- ) {
		v = *p;
		t = 0;
		for (i = 7; i; i--) {
			t <<= 1;
			v >>= 1;
			t |= v & 1;
		}
		*p++ = t;
	}
}

/*
================
SixtetsForIntLittle
================
*/
ID_INLINE static void SixtetsForIntLittle( byte *out, int src) {
	byte *b = (byte *)&src;
	out[0] = ( b[0] & 0xfc ) >> 2;
	out[1] = ( ( b[0] & 0x3 ) << 4 ) + ( ( b[1] & 0xf0 ) >> 4 );
	out[2] = ( ( b[1] & 0xf ) << 2 ) + ( ( b[2] & 0xc0 ) >> 6 );
	out[3] = b[2] & 0x3f;
}

/*
================
SixtetsForIntBig
TTimo: untested - that's the version from initial base64 encode
================
*/
ID_INLINE static void SixtetsForIntBig( byte *out, int src) {
	for( int i = 0 ; i < 4 ; i++ ) {
		out[i] = src & 0x3f;
		src >>= 6;
	}
}

/*
================
IntForSixtetsLittle
================
*/
ID_INLINE static int IntForSixtetsLittle( byte *in ) {
	int ret = 0;
	byte *b = (byte *)&ret;
	b[0] |= in[0] << 2;
	b[0] |= ( in[1] & 0x30 ) >> 4;
	b[1] |= ( in[1] & 0xf ) << 4;
	b[1] |= ( in[2] & 0x3c ) >> 2;
	b[2] |= ( in[2] & 0x3 ) << 6;
	b[2] |= in[3];
	return ret;
}

/*
================
IntForSixtetsBig
TTimo: untested - that's the version from initial base64 decode
================
*/
ID_INLINE static int IntForSixtetsBig( byte *in ) {
	int ret = 0;
	ret |= in[0];
	ret |= in[1] << 6;
	ret |= in[2] << 2*6;
	ret |= in[3] << 3*6;
	return ret;
}

/*
==========
Swap_IsBigEndian
==========
*/
bool Swap_IsBigEndian( void ) {
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
	return false;
#else
	return true;
#endif
}

short	BigShort( short l ) {
	return SDL_SwapBE16(l);
}

short	LittleShort( short l ) {
	return SDL_SwapLE16(l);
}

int		BigInt( int l ) {
	return SDL_SwapBE32(l);
}

int		LittleInt( int l ) {
	return SDL_SwapLE32(l);
}

float	BigFloat( float l ) {
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
	return FloatSwap(l);
#else
	return l;
#endif
}

float	LittleFloat( float l ) {
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
	return l;
#else
	return FloatSwap(l);
#endif
}

void	BigRevBytes( void *bp, int elsize, int elcount ) {
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
	RevBytesSwap(bp, elsize, elcount);
#else
	return;
#endif
}

void	LittleRevBytes( void *bp, int elsize, int elcount ){
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
	return;
#else
	RevBytesSwap(bp, elsize, elcount);
#endif
}

void	LittleBitField( void *bp, int elsize ){
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
	return;
#else
	RevBitFieldSwap(bp, elsize);
#endif
}

void	SixtetsForInt( byte *out, int src) {
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
	SixtetsForIntLittle(out, src);
#else
	SixtetsForIntBig(out, src);
#endif
}

int		IntForSixtets( byte *in ) {
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
	return IntForSixtetsLittle(in);
#else
	return IntForSixtetsBig(in);
#endif
}

/*
===============================================================================

	Assertion

===============================================================================
*/

void AssertFailed( const char *file, int line, const char *expression ) {
	idLib::sys->DebugPrintf( "\n\nASSERTION FAILED!\n%s(%d): '%s'\n", file, line, expression );
#ifdef _MSC_VER
	__debugbreak();
	_exit(1);
#elif defined(__unix__)
	// __builtin_trap() causes an illegal instruction which is kinda ugly.
	// especially if you'd like to be able to continue after the assertion during debugging
	raise(SIGTRAP); // this will break into the debugger.
#elif defined( __GNUC__ )
	__builtin_trap();
	_exit(1);
#endif

}


bool UpdaterDialog::event(QEvent *e)
{
	if((e->type() == QEvent::ActivationChange) && (m_updaterProcess != NULL))
	{
		MUtils::GUI::bring_to_front(m_updaterProcess);
	}
	return QDialog::event(e);
}

// Simple x264 Launcher

#include "win_updater.h"
#include "UIC_win_updater.h"

//Internal
#include "global.h"
#include "model_sysinfo.h"

//MUtils
#include <MUtils/UpdateChecker.h>
#include <MUtils/Hash.h>
#include <MUtils/GUI.h>
#include <MUtils/OSSupport.h>
#include <MUtils/Exception.h>

//Qt
#include <QMovie>
#include <QCloseEvent>
#include <QTimer>
#include <QMessageBox>
#include <QDesktopServices>
#include <QUrl>
#include <QProcess>
#include <QFileInfo>
#include <QDir>
#include <QMap>
#include <QElapsedTimer>

static const char *const DIGEST_KEY = "~Dv/bW3/7t>6?RXVwkaZk-hmS0#O4JS/5YQAO>\\8hvr0B~7[n!X~KMYruemu:MDq";

const UpdaterDialog::binary_t UpdaterDialog::BINARIES[] =
{
	{ "curl.exe", "02f8831c1c93733daf46a4fb183499bc463aa6555214a193937036a1a279e31a65dacef20b4f3b542de5304608688437421a3b4d82cd6b851a245fb5c4f888d1", 1 },
	{ "curl.crt", "bdb150cb424ed84a59ed2df52a0bc584941b21ccc106f629f2fa20d5d7b52a35048dea7bb97e65b97c3077d9436163f999d357785394a8bc8f65f66db4962fa8", 0 },
	{ "vrfy.exe", "91dd35a9d223c42c4c39d8b1ef928c1f0354125a4eefff46a5984082990b3505c272e8d1a4d73b9089ec9c27fb055dab2560a5ebb1d15f323be6615ca0e176d0", 1 },
	{ "wupd.exe", "018a8d0d848407fb0cb530b4540c6f025fd4c280885becd37f83feed8aeb3af6f8e8e0d45066a36549efac7e64706ac1ef09aaa5c75ab8d12c4a70f41518a894", 1 },
	{ NULL, NULL, 0 }
};

#define UPDATE_TEXT(N, TEXT) ui->label_phase##N->setText((TEXT))
#define UPDATE_ICON(N, ICON) ui->icon_phase##N->setPixmap(QIcon(":/buttons/" ICON ".png").pixmap(16, 16))

#define SHOW_ANIMATION(FLAG) do  \
{ \
	ui->frameAnimation->setVisible((FLAG)); \
	ui->labelInfo->setVisible(!(FLAG)); \
	ui->labelUrl->setVisible(!(FLAG)); \
	ui->labelBuildNo->setVisible(!(FLAG)); \
	if((FLAG)) m_animator->start(); else m_animator->stop(); \
} \
while(0)

static inline QString getBin(const QMap<QString, QSharedPointer<QFile>> &binaries, const QString &nameName)
{
	const QSharedPointer<QFile> file = binaries.value(nameName);
	return file.isNull() ? QString() : file->fileName();
}

static void qFileDeleter(QFile *const file)
{
	if(file)
	{
		file->close();
		delete file;
	}
}

// Constructor & Destructor

UpdaterDialog::UpdaterDialog(QWidget *parent, const SysinfoModel *sysinfo, const char *const updateUrl)
:
	QDialog(parent),
	ui(new Ui::UpdaterDialog()),
	m_sysinfo(sysinfo),
	m_updateUrl(updateUrl),
	m_status(MUtils::UpdateChecker::UpdateStatus_NotStartedYet),
	m_thread(NULL),
	m_updaterProcess(NULL),
	m_success(false),
	m_firstShow(true)
{
	//Init the dialog, from the .ui file
	ui->setupUi(this);
	setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint));

	//Scale and fix size
	MUtils::GUI::scale_widget(this);
	setFixedSize(size());

	//Enable buttons
	connect(ui->buttonCancel, SIGNAL(clicked()), this, SLOT(close()));
	connect(ui->buttonDownload, SIGNAL(clicked()), this, SLOT(installUpdate()));
	connect(ui->buttonRetry, SIGNAL(clicked()), this, SLOT(checkForUpdates()));

	//Enable info label
	connect(ui->labelUrl, SIGNAL(linkActivated(QString)), this, SLOT(openUrl(QString)));

	//Init animation
	m_animator.reset(new QMovie(":/images/loading.gif"));
	ui->labelLoadingCenter->setMovie(m_animator.data());

	//Init buttons
	ui->buttonCancel->setEnabled(false);
	ui->buttonRetry->hide();
	ui->buttonDownload->hide();
	ui->labelCancel->hide();

	//Start animation
	SHOW_ANIMATION(true);
}

UpdaterDialog::~UpdaterDialog(void)
{
	if(!m_thread.isNull())
	{
		if(!m_thread->wait(5000))
		{
			m_thread->terminate();
			m_thread->wait();
		}
	}
	delete ui;
}

// Events

void UpdaterDialog::showEvent(QShowEvent *event)
{
	if(m_firstShow)
	{
		m_firstShow = false;
		QTimer::singleShot(16, this, SLOT(initUpdate()));
	}
}

void UpdaterDialog::closeEvent(QCloseEvent *e)
{
	if(!ui->buttonCancel->isEnabled())
	{
		e->ignore();
	}
}

void UpdaterDialog::keyPressEvent(QKeyEvent *event)
{
	switch (event->key())
	{
	case Qt::Key_Escape:
		if ((!m_thread.isNull()) && m_thread->isRunning())
		{
			if (m_status >= MUtils::UpdateChecker::UpdateStatus_FetchingUpdates)
			{
				UPDATE_TEXT(2, tr("Cancellation requested..."));
			}
			else
			{
				UPDATE_TEXT(1, tr("Cancellation requested..."));
			}
			m_thread->cancel();
		}
		break;
	case Qt::Key_F11:
		{
			const QString logFilePath = MUtils::make_temp_file(MUtils::temp_folder(), "txt", true);
			if (!logFilePath.isEmpty())
			{
				qWarning("Write log to: '%s'", MUTILS_UTF8(logFilePath));
				QFile logFile(logFilePath);
				if (logFile.open(QIODevice::WriteOnly | QIODevice::Truncate))
				{
					logFile.write("\xEF\xBB\xBF");
					for (QStringList::ConstIterator iter = m_logFile.constBegin(); iter != m_logFile.constEnd(); iter++)
					{
						logFile.write(iter->toUtf8());
						logFile.write("\r\n");
					}
					logFile.close();
					QDesktopServices::openUrl(QUrl::fromLocalFile(logFile.fileName()));
				}
			}
		}
		break;
	default:
		QDialog::keyPressEvent(event);
	}
}

// Slots

void UpdaterDialog::initUpdate(void)
{
	//Check binary files
	if(!checkBinaries())
	{
		ui->buttonCancel->setEnabled(true);
		const QString message = QString("%1

<nobr>%3</nobr>
").arg(tr("At least one file required by the web-update tool is missing or corrupted.
Please re-install this application and then try again!"), QString::fromLatin1(m_updateUrl), QString::fromLatin1(m_updateUrl).replace("-", "−"));
		if(QMessageBox::critical(this, tr("File Error"), message, tr("Download Latest Version"), tr("Discard")) == 0)
		{
			QDesktopServices::openUrl(QUrl(QString::fromLatin1(m_updateUrl)));
		}
		close();
		return;
	}

	//Make sure user does have admin access
	if(!MUtils::OS::user_is_admin())
	{
		qWarning("User is not in the \"admin\" group, cannot update!");
		QString message;
		message += QString("<nobr>%1</nobr>
").arg(tr("Sorry, but only users in the \"Administrators\" group can install updates."));
		message += QString("<nobr>%1</nobr>").arg(tr("Please start application from an administrator account and try again!"));
		if(QMessageBox::critical(this, this->windowTitle(), message, tr("Discard"), tr("Ignore")) != 1)
		{
			ui->buttonCancel->setEnabled(true);
			close();
			return;
		}
	}

	//Create and setup thread
	if(!m_thread)
	{
		m_thread.reset(new MUtils::UpdateChecker(getBin(m_binaries, "curl.exe"), getBin(m_binaries, "vrfy.exe"), "Simple x264 Launcher", x264_version_build(), false));
		connect(m_thread.data(), SIGNAL(statusChanged(int)), this, SLOT(threadStatusChanged(int)));
		connect(m_thread.data(), SIGNAL(finished()), this, SLOT(threadFinished()));
		connect(m_thread.data(), SIGNAL(terminated()), this, SLOT(threadFinished()));
		connect(m_thread.data(), SIGNAL(messageLogged(QString)), this, SLOT(threadMessageLogged(QString)));
	}

	//Begin updater run
	QTimer::singleShot(16, this, SLOT(checkForUpdates()));
}

void UpdaterDialog::checkForUpdates(void)
{
	if((!m_thread) || m_thread->isRunning())
	{
		qWarning("Update in progress, cannot check for updates now!");
	}

	//Clear texts
	ui->retranslateUi(this);
	ui->labelBuildNo->setText(tr("Installed build is #%1  |  Latest build is #%2").arg(QString::number(x264_version_build()), tr("N/A")));

	//Init buttons
	ui->buttonCancel->setEnabled(false);
	ui->buttonRetry->hide();
	ui->buttonDownload->hide();

	//Hide labels
	ui->labelInfo->hide();
	ui->labelUrl->hide();
	ui->labelCancel->show();

	//Update status
	threadStatusChanged(MUtils::UpdateChecker::UpdateStatus_NotStartedYet);

	//Start animation
	SHOW_ANIMATION(true);

	//Update cursor
	QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
	QApplication::setOverrideCursor(Qt::WaitCursor);

	//Clear log
	m_logFile.clear();

	//Init timer
	m_elapsed.reset(new QElapsedTimer());
	m_elapsed->start();

	//Start the updater thread
	QTimer::singleShot(125, m_thread.data(), SLOT(start()));
}

void UpdaterDialog::threadStatusChanged(int status)
{
	const int prevStatus = m_status;
	switch(m_status = status)
	{
	case MUtils::UpdateChecker::UpdateStatus_NotStartedYet:
		UPDATE_ICON(1, "clock");
		UPDATE_ICON(2, "clock");
		UPDATE_ICON(3, "clock");
		break;
	case MUtils::UpdateChecker::UpdateStatus_CheckingConnection:
		UPDATE_ICON(1, "play");
		break;
	case MUtils::UpdateChecker::UpdateStatus_FetchingUpdates:
		UPDATE_ICON(1, "shield_green");
		UPDATE_TEXT(1, tr("Internet connection is working."));
		UPDATE_ICON(2, "play");
		break;
	case MUtils::UpdateChecker::UpdateStatus_ErrorNoConnection:
		UPDATE_ICON(1, "shield_error");
		UPDATE_TEXT(1, tr("Computer is currently offline!"));
		UPDATE_ICON(2, "shield_grey");
		UPDATE_ICON(3, "shield_grey");
		break;
	case MUtils::UpdateChecker::UpdateStatus_ErrorConnectionTestFailed:
		UPDATE_ICON(1, "shield_error");
		UPDATE_TEXT(1, tr("Internet connectivity test failed!"));
		UPDATE_ICON(2, "shield_grey");
		UPDATE_ICON(3, "shield_grey");
		break;
	case MUtils::UpdateChecker::UpdateStatus_ErrorFetchUpdateInfo:
		UPDATE_ICON(2, "shield_error");
		UPDATE_TEXT(2, tr("Failed to download the update information!"));
		UPDATE_ICON(3, "shield_grey");
		break;
	case MUtils::UpdateChecker::UpdateStatus_CompletedUpdateAvailable:
	case MUtils::UpdateChecker::UpdateStatus_CompletedNoUpdates:
	case MUtils::UpdateChecker::UpdateStatus_CompletedNewVersionOlder:
		UPDATE_ICON(2, "shield_green");
		UPDATE_TEXT(2, tr("Update information received successfully."));
		UPDATE_ICON(3, "play");
		break;
	case MUtils::UpdateChecker::UpdateStatus_CancelledByUser:
		if (prevStatus >= MUtils::UpdateChecker::UpdateStatus_FetchingUpdates)
		{
			UPDATE_ICON(2, "shield_error");
			UPDATE_TEXT(2, tr("Operation was cancelled by the user!"));
			UPDATE_ICON(3, "shield_grey");
		}
		else
		{
			UPDATE_ICON(1, "shield_error");
			UPDATE_TEXT(1, tr("Operation was cancelled by the user!"));
			UPDATE_ICON(2, "shield_grey");
			UPDATE_ICON(3, "shield_grey");
		}
		break;
	default:
		MUTILS_THROW("Unknown status code!");
	}
}

void UpdaterDialog::threadFinished(void)
{
	m_success = m_thread->getSuccess();
	ui->labelCancel->hide();
	QTimer::singleShot((m_success ? 500 : 0), this, SLOT(updateFinished()));
}

void UpdaterDialog::updateFinished(void)
{
	//Query the timer, if available
	if (!m_elapsed.isNull())
	{
		const quint64 elapsed = m_elapsed->restart();
		qDebug("Update check completed after %.2f seconds.", double(elapsed) / 1000.0);
	}

	//Restore cursor
	QApplication::restoreOverrideCursor();

	//If update was successfull, process final updater state
	if(m_thread->getSuccess())
	{
		switch(m_status)
		{
		case MUtils::UpdateChecker::UpdateStatus_CompletedUpdateAvailable:
			UPDATE_ICON(3, "shield_exclamation");
			UPDATE_TEXT(3, tr("A newer version is available!"));
			ui->buttonDownload->show();
			break;
		case MUtils::UpdateChecker::UpdateStatus_CompletedNoUpdates:
			UPDATE_ICON(3, "shield_green");
			UPDATE_TEXT(3, tr("Your version is up-to-date."));
			break;
		case MUtils::UpdateChecker::UpdateStatus_CompletedNewVersionOlder:
			UPDATE_ICON(3, "shield_blue");
			UPDATE_TEXT(3, tr("You are using a pre-release version!"));
			break;
		default:
			qWarning("Update thread succeeded with unexpected status code: %d", m_status);
		}
	}

	//Show update info or retry button
	switch(m_status)
	{
	case MUtils::UpdateChecker::UpdateStatus_CompletedUpdateAvailable:
	case MUtils::UpdateChecker::UpdateStatus_CompletedNoUpdates:
	case MUtils::UpdateChecker::UpdateStatus_CompletedNewVersionOlder:
		SHOW_ANIMATION(false);
		ui->labelBuildNo->setText(tr("Installed build is #%1  |  Latest build is #%2").arg(QString::number(x264_version_build()), QString::number(m_thread->getUpdateInfo()->getBuildNo())));
		ui->labelUrl->setText(QString("%1").arg(m_thread->getUpdateInfo()->getDownloadSite()));
		break;
	case MUtils::UpdateChecker::UpdateStatus_ErrorNoConnection:
	case MUtils::UpdateChecker::UpdateStatus_ErrorConnectionTestFailed:
	case MUtils::UpdateChecker::UpdateStatus_ErrorFetchUpdateInfo:
	case MUtils::UpdateChecker::UpdateStatus_CancelledByUser:
		m_animator->stop();
		ui->buttonRetry->show();
		break;
	default:
		qWarning("Update thread finished with unexpected status code: %d", m_status);
	}

	//Re-enbale cancel button
	ui->buttonCancel->setEnabled(true);

}

void UpdaterDialog::threadMessageLogged(const QString &message)
{
	m_logFile << message;
}

void UpdaterDialog::openUrl(const QString &url)
{
	qDebug("Open URL: %s", url.toLatin1().constData());
	QDesktopServices::openUrl(QUrl(url));
}

void UpdaterDialog::installUpdate(void)
{
	if(!((m_thread) && m_thread->getSuccess()))
	{
		qWarning("Cannot download/install update at this point!");
		return;
	}

	QApplication::setOverrideCursor(Qt::WaitCursor);
	ui->buttonDownload->hide();
	ui->buttonCancel->setEnabled(false);
	SHOW_ANIMATION(true);

	const MUtils::UpdateCheckerInfo *updateInfo = m_thread->getUpdateInfo();

	QProcess process;
	QStringList args;
	QEventLoop loop;

	MUtils::init_process(process, MUtils::temp_folder(), false);

	connect(&process, SIGNAL(error(QProcess::ProcessError)), &loop, SLOT(quit()));
	connect(&process, SIGNAL(finished(int,QProcess::ExitStatus)), &loop, SLOT(quit()));

	args << QString("/Location=%1").arg(updateInfo->getDownloadAddress());
	args << QString("/Filename=%1").arg(updateInfo->getDownloadFilename());
	args << QString("/TicketID=%1").arg(updateInfo->getDownloadFilecode());
	args << QString("/CheckSum=%1").arg(updateInfo->getDownloadChecksum());
	args << QString("/ToFolder=%1").arg(QDir::toNativeSeparators(QDir(QApplication::applicationDirPath()).canonicalPath()));
	args << QString("/ToExFile=%1.exe").arg(QFileInfo(QFileInfo(QApplication::applicationFilePath()).canonicalFilePath()).completeBaseName());
	args << QString("/AppTitle=Simple x264 Launcher (Build #%1)").arg(QString::number(updateInfo->getBuildNo()));

	process.start(getBin(m_binaries, "wupd.exe"), args);
	if(!process.waitForStarted())
	{
		QApplication::restoreOverrideCursor();
		SHOW_ANIMATION(false);
		QMessageBox::critical(this, tr("Update Failed"), tr("Sorry, failed to launch web-update program!"));
		ui->buttonDownload->show();
		ui->buttonCancel->setEnabled(true);
		return;
	}

	m_updaterProcess = MUtils::OS::process_id(&process);
	loop.exec(QEventLoop::ExcludeUserInputEvents);

	if(!process.waitForFinished())
	{
		process.kill();
		process.waitForFinished();
	}

	m_updaterProcess = NULL;
	QApplication::restoreOverrideCursor();
	ui->buttonDownload->show();
	ui->buttonCancel->setEnabled(true);
	SHOW_ANIMATION(false);

	if(process.exitCode() == 0)
	{
		done(READY_TO_INSTALL_UPDATE);
	}
}

// Private Functions

bool UpdaterDialog::checkBinaries(void)
{
	qDebug("[File Verification]");
	for(size_t i = 0; BINARIES[i].name; i++)
	{
		const QString name = QString::fromLatin1(BINARIES[i].name);
		if (!m_binaries.contains(name))
		{
			QScopedPointer<QFile> binary(new QFile(QString("%1/toolset/common/%2").arg(m_sysinfo->getAppPath(), name)));
			if (binary->open(QIODevice::ReadOnly))
			{
				if (checkFileHash(binary->fileName(), BINARIES[i].hash))
				{
					QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
					m_binaries.insert(name, QSharedPointer<QFile>(binary.take(), qFileDeleter));
				}
				else
				{
					qWarning("Verification of '%s' has failed!", MUTILS_UTF8(name));
					binary->close();
					return false;
				}
			}
			else
			{
				qWarning("File '%s' could not be opened!", MUTILS_UTF8(name));
				return false;
			}
		}
	}
	qDebug("File check completed.\n");
	return true;
}

bool UpdaterDialog::checkFileHash(const QString &filePath, const char *expectedHash)
{
	qDebug("Checking file: %s", MUTILS_UTF8(filePath));
	QScopedPointer<MUtils::Hash::Hash> checksum(MUtils::Hash::create(MUtils::Hash::HASH_BLAKE2_512, DIGEST_KEY));
	QFile file(filePath);
	if(file.open(QIODevice::ReadOnly))
	{
		checksum->update(file);
		const QByteArray fileHash = checksum->digest();
		if((strlen(expectedHash) != fileHash.size()) || (memcmp(fileHash.constData(), expectedHash, fileHash.size()) != 0))
		{
			qWarning("\nFile appears to be corrupted:\n%s\n", filePath.toUtf8().constData());
			qWarning("Expected Hash: %s\nDetected Hash: %s\n", expectedHash, fileHash.constData());
			return false;
		}
		return true;
	}
	else
	{
		qWarning("Failed to open file:\n%s\n", filePath.toUtf8().constData());
		return false;
	}
}


Complex(int r, int i): real(r), imag(i) {}

/*
* 题目名称：复数集合
* 题目来源：北京邮电大学复试上机题
* 题目链接：http://example.com
* 代码作者：杨泽邦(炉灰)
*/

#include <iostream>
#include <cstdio>
#include <queue>
#include <string>

using namespace std;

struct Complex {
    int real;                                   //实部
    int imag;                                   //虚部

    bool operator< (Complex c) const {          //重载小于号
        if (real * real + imag * imag == c.real * c.real + c.imag * c.imag) {
            return imag > c.imag;
        } else {
            return real * real + imag * imag < c.real * c.real + c.imag * c.imag;
        }
    }
};

int main() {
    int n;
    while (scanf("%d", &n) != EOF) {
        priority_queue<Complex> myPriorityQueue;
        while (n--) {
            string str;
            cin >> str;
            if (str == "Pop") {
                if (myPriorityQueue.empty()) {
                    printf("empty\n");
                } else {
                    Complex current = myPriorityQueue.top();
                    myPriorityQueue.pop();
                    printf("%d+i%d\n", current.real, current.imag);
                    printf("SIZE = %d\n", myPriorityQueue.size());
                }
            } else {
                int a, b;
                scanf("%d+i%d", &a, &b);
                myPriorityQueue.push(Complex(a, b));
                printf("SIZE = %d\n", myPriorityQueue.size());
            }
        }
    }
    return 0;
}


static MCDisassembler *createSystemZDisassembler(const Target &T,
                                                 const MCSubtargetInfo &STI,
                                                 MCContext &Ctx) {
  return new SystemZDisassembler(STI, Ctx);
}

//                     The LLVM Compiler Infrastructure

#include "MCTargetDesc/SystemZMCTargetDesc.h"
#include "SystemZ.h"
#include "llvm/MC/MCDisassembler/MCDisassembler.h"
#include "llvm/MC/MCFixedLenDisassembler.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/TargetRegistry.h"
#include <cassert>
#include <cstdint>

using namespace llvm;

#define DEBUG_TYPE "systemz-disassembler"

typedef MCDisassembler::DecodeStatus DecodeStatus;

namespace {

class SystemZDisassembler : public MCDisassembler {
public:
  SystemZDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx)
    : MCDisassembler(STI, Ctx) {}
  ~SystemZDisassembler() override = default;

  DecodeStatus getInstruction(MCInst &instr, uint64_t &Size,
                              ArrayRef<uint8_t> Bytes, uint64_t Address,
                              raw_ostream &VStream,
                              raw_ostream &CStream) const override;
};

} // end anonymous namespace

extern "C" void LLVMInitializeSystemZDisassembler() {
  // Register the disassembler.
  TargetRegistry::RegisterMCDisassembler(getTheSystemZTarget(),
                                         createSystemZDisassembler);
}

/// tryAddingSymbolicOperand - trys to add a symbolic operand in place of the
/// immediate Value in the MCInst.
/// @param Value      - The immediate Value, has had any PC adjustment made by
/// @param isBranch   - If the instruction is a branch instruction
/// @param Address    - The starting address of the instruction
/// @param Offset     - The byte offset to this immediate in the instruction
/// @param Width      - The byte width of this immediate in the instruction
/// If the getOpInfo() function was set when setupForSymbolicDisassembly() was
/// called then that function is called to get any symbolic information for the
/// immediate in the instruction using the Address, Offset and Width.  If that
/// returns non-zero then the symbolic information it returns is used to create
/// an MCExpr and that is added as an operand to the MCInst.  If getOpInfo()
/// returns zero and isBranch is true then a symbol look up for immediate Value
/// is done and if a symbol is found an MCExpr is created with that, else
/// an MCExpr with the immediate Value is created.  This function returns true
/// if it adds an operand to the MCInst and false otherwise.
static bool tryAddingSymbolicOperand(int64_t Value, bool isBranch,
                                     uint64_t Address, uint64_t Offset,
                                     uint64_t Width, MCInst &MI,
                                     const void *Decoder) {
  const MCDisassembler *Dis = static_cast<const MCDisassembler*>(Decoder);
  return Dis->tryAddingSymbolicOperand(MI, Value, Address, isBranch,
                                       Offset, Width);
}

static DecodeStatus decodeRegisterClass(MCInst &Inst, uint64_t RegNo,
                                        const unsigned *Regs, unsigned Size) {
  assert(RegNo < Size && "Invalid register");
  RegNo = Regs[RegNo];
  if (RegNo == 0)
    return MCDisassembler::Fail;
  Inst.addOperand(MCOperand::createReg(RegNo));
  return MCDisassembler::Success;
}

static DecodeStatus DecodeGR32BitRegisterClass(MCInst &Inst, uint64_t RegNo,
                                               uint64_t Address,
                                               const void *Decoder) {
  return decodeRegisterClass(Inst, RegNo, SystemZMC::GR32Regs, 16);
}

static DecodeStatus DecodeGRH32BitRegisterClass(MCInst &Inst, uint64_t RegNo,
                                                uint64_t Address,
                                                const void *Decoder) {
  return decodeRegisterClass(Inst, RegNo, SystemZMC::GRH32Regs, 16);
}

static DecodeStatus DecodeGR64BitRegisterClass(MCInst &Inst, uint64_t RegNo,
                                               uint64_t Address,
                                               const void *Decoder) {
  return decodeRegisterClass(Inst, RegNo, SystemZMC::GR64Regs, 16);
}

static DecodeStatus DecodeGR128BitRegisterClass(MCInst &Inst, uint64_t RegNo,
                                                uint64_t Address,
                                                const void *Decoder) {
  return decodeRegisterClass(Inst, RegNo, SystemZMC::GR128Regs, 16);
}

static DecodeStatus DecodeADDR64BitRegisterClass(MCInst &Inst, uint64_t RegNo,
                                                 uint64_t Address,
                                                 const void *Decoder) {
  return decodeRegisterClass(Inst, RegNo, SystemZMC::GR64Regs, 16);
}

static DecodeStatus DecodeFP32BitRegisterClass(MCInst &Inst, uint64_t RegNo,
                                               uint64_t Address,
                                               const void *Decoder) {
  return decodeRegisterClass(Inst, RegNo, SystemZMC::FP32Regs, 16);
}

static DecodeStatus DecodeFP64BitRegisterClass(MCInst &Inst, uint64_t RegNo,
                                               uint64_t Address,
                                               const void *Decoder) {
  return decodeRegisterClass(Inst, RegNo, SystemZMC::FP64Regs, 16);
}

static DecodeStatus DecodeFP128BitRegisterClass(MCInst &Inst, uint64_t RegNo,
                                                uint64_t Address,
                                                const void *Decoder) {
  return decodeRegisterClass(Inst, RegNo, SystemZMC::FP128Regs, 16);
}

static DecodeStatus DecodeVR32BitRegisterClass(MCInst &Inst, uint64_t RegNo,
                                               uint64_t Address,
                                               const void *Decoder) {
  return decodeRegisterClass(Inst, RegNo, SystemZMC::VR32Regs, 32);
}

static DecodeStatus DecodeVR64BitRegisterClass(MCInst &Inst, uint64_t RegNo,
                                               uint64_t Address,
                                               const void *Decoder) {
  return decodeRegisterClass(Inst, RegNo, SystemZMC::VR64Regs, 32);
}

static DecodeStatus DecodeVR128BitRegisterClass(MCInst &Inst, uint64_t RegNo,
                                                uint64_t Address,
                                                const void *Decoder) {
  return decodeRegisterClass(Inst, RegNo, SystemZMC::VR128Regs, 32);
}

static DecodeStatus DecodeAR32BitRegisterClass(MCInst &Inst, uint64_t RegNo,
                                               uint64_t Address,
                                               const void *Decoder) {
  return decodeRegisterClass(Inst, RegNo, SystemZMC::AR32Regs, 16);
}

static DecodeStatus DecodeCR64BitRegisterClass(MCInst &Inst, uint64_t RegNo,
                                               uint64_t Address,
                                               const void *Decoder) {
  return decodeRegisterClass(Inst, RegNo, SystemZMC::CR64Regs, 16);
}

template<unsigned N>
static DecodeStatus decodeUImmOperand(MCInst &Inst, uint64_t Imm) {
  if (!isUInt<N>(Imm))
    return MCDisassembler::Fail;
  Inst.addOperand(MCOperand::createImm(Imm));
  return MCDisassembler::Success;
}

template<unsigned N>
static DecodeStatus decodeSImmOperand(MCInst &Inst, uint64_t Imm) {
  if (!isUInt<N>(Imm))
    return MCDisassembler::Fail;
  Inst.addOperand(MCOperand::createImm(SignExtend64<N>(Imm)));
  return MCDisassembler::Success;
}

static DecodeStatus decodeU1ImmOperand(MCInst &Inst, uint64_t Imm,
                                       uint64_t Address, const void *Decoder) {
  return decodeUImmOperand<1>(Inst, Imm);
}

static DecodeStatus decodeU2ImmOperand(MCInst &Inst, uint64_t Imm,
                                       uint64_t Address, const void *Decoder) {
  return decodeUImmOperand<2>(Inst, Imm);
}

static DecodeStatus decodeU3ImmOperand(MCInst &Inst, uint64_t Imm,
                                       uint64_t Address, const void *Decoder) {
  return decodeUImmOperand<3>(Inst, Imm);
}

static DecodeStatus decodeU4ImmOperand(MCInst &Inst, uint64_t Imm,
                                       uint64_t Address, const void *Decoder) {
  return decodeUImmOperand<4>(Inst, Imm);
}

static DecodeStatus decodeU6ImmOperand(MCInst &Inst, uint64_t Imm,
                                       uint64_t Address, const void *Decoder) {
  return decodeUImmOperand<6>(Inst, Imm);
}

static DecodeStatus decodeU8ImmOperand(MCInst &Inst, uint64_t Imm,
                                       uint64_t Address, const void *Decoder) {
  return decodeUImmOperand<8>(Inst, Imm);
}

static DecodeStatus decodeU12ImmOperand(MCInst &Inst, uint64_t Imm,
                                        uint64_t Address, const void *Decoder) {
  return decodeUImmOperand<12>(Inst, Imm);
}

static DecodeStatus decodeU16ImmOperand(MCInst &Inst, uint64_t Imm,
                                        uint64_t Address, const void *Decoder) {
  return decodeUImmOperand<16>(Inst, Imm);
}

static DecodeStatus decodeU32ImmOperand(MCInst &Inst, uint64_t Imm,
                                        uint64_t Address, const void *Decoder) {
  return decodeUImmOperand<32>(Inst, Imm);
}

static DecodeStatus decodeS8ImmOperand(MCInst &Inst, uint64_t Imm,
                                       uint64_t Address, const void *Decoder) {
  return decodeSImmOperand<8>(Inst, Imm);
}

static DecodeStatus decodeS16ImmOperand(MCInst &Inst, uint64_t Imm,
                                        uint64_t Address, const void *Decoder) {
  return decodeSImmOperand<16>(Inst, Imm);
}

static DecodeStatus decodeS32ImmOperand(MCInst &Inst, uint64_t Imm,
                                        uint64_t Address, const void *Decoder) {
  return decodeSImmOperand<32>(Inst, Imm);
}

template<unsigned N>
static DecodeStatus decodePCDBLOperand(MCInst &Inst, uint64_t Imm,
                                       uint64_t Address,
                                       bool isBranch,
                                       const void *Decoder) {
  assert(isUInt<N>(Imm) && "Invalid PC-relative offset");
  uint64_t Value = SignExtend64<N>(Imm) * 2 + Address;

  if (!tryAddingSymbolicOperand(Value, isBranch, Address, 2, N / 8,
                                Inst, Decoder))
    Inst.addOperand(MCOperand::createImm(Value));

  return MCDisassembler::Success;
}

static DecodeStatus decodePC12DBLBranchOperand(MCInst &Inst, uint64_t Imm,
                                               uint64_t Address,
                                               const void *Decoder) {
  return decodePCDBLOperand<12>(Inst, Imm, Address, true, Decoder);
}

static DecodeStatus decodePC16DBLBranchOperand(MCInst &Inst, uint64_t Imm,
                                               uint64_t Address,
                                               const void *Decoder) {
  return decodePCDBLOperand<16>(Inst, Imm, Address, true, Decoder);
}

static DecodeStatus decodePC24DBLBranchOperand(MCInst &Inst, uint64_t Imm,
                                               uint64_t Address,
                                               const void *Decoder) {
  return decodePCDBLOperand<24>(Inst, Imm, Address, true, Decoder);
}

static DecodeStatus decodePC32DBLBranchOperand(MCInst &Inst, uint64_t Imm,
                                               uint64_t Address,
                                               const void *Decoder) {
  return decodePCDBLOperand<32>(Inst, Imm, Address, true, Decoder);
}

static DecodeStatus decodePC32DBLOperand(MCInst &Inst, uint64_t Imm,
                                         uint64_t Address,
                                         const void *Decoder) {
  return decodePCDBLOperand<32>(Inst, Imm, Address, false, Decoder);
}

static DecodeStatus decodeBDAddr12Operand(MCInst &Inst, uint64_t Field,
                                          const unsigned *Regs) {
  uint64_t Base = Field >> 12;
  uint64_t Disp = Field & 0xfff;
  assert(Base < 16 && "Invalid BDAddr12");
  Inst.addOperand(MCOperand::createReg(Base == 0 ? 0 : Regs[Base]));
  Inst.addOperand(MCOperand::createImm(Disp));
  return MCDisassembler::Success;
}

static DecodeStatus decodeBDAddr20Operand(MCInst &Inst, uint64_t Field,
                                          const unsigned *Regs) {
  uint64_t Base = Field >> 20;
  uint64_t Disp = ((Field << 12) & 0xff000) | ((Field >> 8) & 0xfff);
  assert(Base < 16 && "Invalid BDAddr20");
  Inst.addOperand(MCOperand::createReg(Base == 0 ? 0 : Regs[Base]));
  Inst.addOperand(MCOperand::createImm(SignExtend64<20>(Disp)));
  return MCDisassembler::Success;
}

static DecodeStatus decodeBDXAddr12Operand(MCInst &Inst, uint64_t Field,
                                           const unsigned *Regs) {
  uint64_t Index = Field >> 16;
  uint64_t Base = (Field >> 12) & 0xf;
  uint64_t Disp = Field & 0xfff;
  assert(Index < 16 && "Invalid BDXAddr12");
  Inst.addOperand(MCOperand::createReg(Base == 0 ? 0 : Regs[Base]));
  Inst.addOperand(MCOperand::createImm(Disp));
  Inst.addOperand(MCOperand::createReg(Index == 0 ? 0 : Regs[Index]));
  return MCDisassembler::Success;
}

static DecodeStatus decodeBDXAddr20Operand(MCInst &Inst, uint64_t Field,
                                           const unsigned *Regs) {
  uint64_t Index = Field >> 24;
  uint64_t Base = (Field >> 20) & 0xf;
  uint64_t Disp = ((Field & 0xfff00) >> 8) | ((Field & 0xff) << 12);
  assert(Index < 16 && "Invalid BDXAddr20");
  Inst.addOperand(MCOperand::createReg(Base == 0 ? 0 : Regs[Base]));
  Inst.addOperand(MCOperand::createImm(SignExtend64<20>(Disp)));
  Inst.addOperand(MCOperand::createReg(Index == 0 ? 0 : Regs[Index]));
  return MCDisassembler::Success;
}

static DecodeStatus decodeBDLAddr12Len4Operand(MCInst &Inst, uint64_t Field,
                                               const unsigned *Regs) {
  uint64_t Length = Field >> 16;
  uint64_t Base = (Field >> 12) & 0xf;
  uint64_t Disp = Field & 0xfff;
  assert(Length < 16 && "Invalid BDLAddr12Len4");
  Inst.addOperand(MCOperand::createReg(Base == 0 ? 0 : Regs[Base]));
  Inst.addOperand(MCOperand::createImm(Disp));
  Inst.addOperand(MCOperand::createImm(Length + 1));
  return MCDisassembler::Success;
}

static DecodeStatus decodeBDLAddr12Len8Operand(MCInst &Inst, uint64_t Field,
                                               const unsigned *Regs) {
  uint64_t Length = Field >> 16;
  uint64_t Base = (Field >> 12) & 0xf;
  uint64_t Disp = Field & 0xfff;
  assert(Length < 256 && "Invalid BDLAddr12Len8");
  Inst.addOperand(MCOperand::createReg(Base == 0 ? 0 : Regs[Base]));
  Inst.addOperand(MCOperand::createImm(Disp));
  Inst.addOperand(MCOperand::createImm(Length + 1));
  return MCDisassembler::Success;
}

static DecodeStatus decodeBDRAddr12Operand(MCInst &Inst, uint64_t Field,
                                           const unsigned *Regs) {
  uint64_t Length = Field >> 16;
  uint64_t Base = (Field >> 12) & 0xf;
  uint64_t Disp = Field & 0xfff;
  assert(Length < 16 && "Invalid BDRAddr12");
  Inst.addOperand(MCOperand::createReg(Base == 0 ? 0 : Regs[Base]));
  Inst.addOperand(MCOperand::createImm(Disp));
  Inst.addOperand(MCOperand::createReg(Regs[Length]));
  return MCDisassembler::Success;
}

static DecodeStatus decodeBDVAddr12Operand(MCInst &Inst, uint64_t Field,
                                           const unsigned *Regs) {
  uint64_t Index = Field >> 16;
  uint64_t Base = (Field >> 12) & 0xf;
  uint64_t Disp = Field & 0xfff;
  assert(Index < 32 && "Invalid BDVAddr12");
  Inst.addOperand(MCOperand::createReg(Base == 0 ? 0 : Regs[Base]));
  Inst.addOperand(MCOperand::createImm(Disp));
  Inst.addOperand(MCOperand::createReg(SystemZMC::VR128Regs[Index]));
  return MCDisassembler::Success;
}

static DecodeStatus decodeBDAddr32Disp12Operand(MCInst &Inst, uint64_t Field,
                                                uint64_t Address,
                                                const void *Decoder) {
  return decodeBDAddr12Operand(Inst, Field, SystemZMC::GR32Regs);
}

static DecodeStatus decodeBDAddr32Disp20Operand(MCInst &Inst, uint64_t Field,
                                                uint64_t Address,
                                                const void *Decoder) {
  return decodeBDAddr20Operand(Inst, Field, SystemZMC::GR32Regs);
}

static DecodeStatus decodeBDAddr64Disp12Operand(MCInst &Inst, uint64_t Field,
                                                uint64_t Address,
                                                const void *Decoder) {
  return decodeBDAddr12Operand(Inst, Field, SystemZMC::GR64Regs);
}

static DecodeStatus decodeBDAddr64Disp20Operand(MCInst &Inst, uint64_t Field,
                                                uint64_t Address,
                                                const void *Decoder) {
  return decodeBDAddr20Operand(Inst, Field, SystemZMC::GR64Regs);
}

static DecodeStatus decodeBDXAddr64Disp12Operand(MCInst &Inst, uint64_t Field,
                                                 uint64_t Address,
                                                 const void *Decoder) {
  return decodeBDXAddr12Operand(Inst, Field, SystemZMC::GR64Regs);
}

static DecodeStatus decodeBDXAddr64Disp20Operand(MCInst &Inst, uint64_t Field,
                                                 uint64_t Address,
                                                 const void *Decoder) {
  return decodeBDXAddr20Operand(Inst, Field, SystemZMC::GR64Regs);
}

static DecodeStatus decodeBDLAddr64Disp12Len4Operand(MCInst &Inst,
                                                     uint64_t Field,
                                                     uint64_t Address,
                                                     const void *Decoder) {
  return decodeBDLAddr12Len4Operand(Inst, Field, SystemZMC::GR64Regs);
}

static DecodeStatus decodeBDLAddr64Disp12Len8Operand(MCInst &Inst,
                                                     uint64_t Field,
                                                     uint64_t Address,
                                                     const void *Decoder) {
  return decodeBDLAddr12Len8Operand(Inst, Field, SystemZMC::GR64Regs);
}

static DecodeStatus decodeBDRAddr64Disp12Operand(MCInst &Inst,
                                                 uint64_t Field,
                                                 uint64_t Address,
                                                 const void *Decoder) {
  return decodeBDRAddr12Operand(Inst, Field, SystemZMC::GR64Regs);
}

static DecodeStatus decodeBDVAddr64Disp12Operand(MCInst &Inst, uint64_t Field,
                                                 uint64_t Address,
                                                 const void *Decoder) {
  return decodeBDVAddr12Operand(Inst, Field, SystemZMC::GR64Regs);
}

#include "SystemZGenDisassemblerTables.inc"

DecodeStatus SystemZDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
                                                 ArrayRef<uint8_t> Bytes,
                                                 uint64_t Address,
                                                 raw_ostream &OS,
                                                 raw_ostream &CS) const {
  // Get the first two bytes of the instruction.
  Size = 0;
  if (Bytes.size() < 2)
    return MCDisassembler::Fail;

  // The top 2 bits of the first byte specify the size.
  const uint8_t *Table;
  if (Bytes[0] < 0x40) {
    Size = 2;
    Table = DecoderTable16;
  } else if (Bytes[0] < 0xc0) {
    Size = 4;
    Table = DecoderTable32;
  } else {
    Size = 6;
    Table = DecoderTable48;
  }

  // Read any remaining bytes.
  if (Bytes.size() < Size)
    return MCDisassembler::Fail;

  // Construct the instruction.
  uint64_t Inst = 0;
  for (uint64_t I = 0; I < Size; ++I)
    Inst = (Inst << 8) | Bytes[I];

  return decodeInstruction(Table, MI, Inst, Address, this, STI);
}


try {
        auto results = tallyResults();
        auto resultCount = results.size();
        populateResults(context.getResults().initResults(resultCount), kj::mv(results));
    } catch (fc::exception& e) {
        edump((e.to_detail_string()));
    }

/*
 * This file is part of The Follow My Vote Stake-Weighted Voting Application ("SWV").
 *
 */

#include "LiveContestResultsServer.hpp"
#include "SnapshotDecisionGenerator.hpp"
#include "VoteDatabase.hpp"

#include <kj/debug.h>

#include <iostream>

namespace swv {

LiveContestResultsServer::LiveContestResultsServer(VoteDatabase& vdb, gch::operation_history_id_type contestId)
    : vdb(vdb), contestId(contestId) {}

int64_t LiveContestResultsServer::totalVotingStake() {
    auto results = tallyResults();
    return std::accumulate(results.begin(), results.end(), gch::share_type(),
                           [](gch::share_type sum, const auto& result) {
        return sum + result.second;
    }).value;
}

::kj::Promise<void> LiveContestResultsServer::results(ContestResults::Server::ResultsContext context) {
    KJ_LOG(DBG, __FUNCTION__, context.getParams());

    return kj::READY_NOW;
}

::kj::Promise<void> LiveContestResultsServer::subscribe(ContestResults::Server::SubscribeContext context) {
    KJ_LOG(DBG, __FUNCTION__, context.getParams());
    try {
        notifiers.emplace_back(context.getParams().getNotifier());
        subscriptions.emplace_back(vdb.db().applied_block.connect([this] (const gch::signed_block&) mutable -> void {
            try {
                for (auto& notifier : notifiers) {
                    auto request = notifier.notifyRequest();
                    auto results = tallyResults();
                    auto resultCount = results.size();
                    populateResults(request.initNotification(resultCount),
                                    kj::mv(results));
                    request.send();
                }
            } catch (kj::Exception& e) {
                KJ_LOG(ERROR, "Exception in results notifier", e);
            }
        }));
    } catch (fc::exception& e) {
        edump((e.to_detail_string()));
    }

    return kj::READY_NOW;
}

::kj::Promise<void> LiveContestResultsServer::decisions(ContestResults::Server::DecisionsContext context) {
    KJ_LOG(DBG, __FUNCTION__, context.getParams());
    context.getResults().setDecisionGenerator(kj::heap<SnapshotDecisionGenerator>(contestId, vdb));
    return kj::READY_NOW;
}

const Contest& LiveContestResultsServer::getContest() {
    auto& index = vdb.contestIndex().indices().get<ById>();
    auto itr = index.find(contestId);
    KJ_REQUIRE(itr != index.end(), "No contest with the specified ID was found.");
    return *itr;
}

LiveContestResultsServer::Results LiveContestResultsServer::tallyResults() {
    Results results;

    /*
     * We need to tally the results on the contest. The decisions-by-contest index orders decisions by contest, then by
     * voter, then by order of creation. We need to examine the most recent decision each voter who has voted on this
     * contest has published. So the algorithm is:
     *
     * Let C = the contest being tallied
     * For each voter V who has cast any decisions on C:
     *   Let D = last decision V cast on C
     *   Add D to tally
     */

    const auto& contest = getContest();
    auto contestantCount = contest.contestants.size();
    auto& index = vdb.decisionIndex().indices().get<ByContest>();
    // Find the first decision on this contest and get its voter
    auto begin = index.lower_bound(boost::make_tuple(contestId));

    // begin now points to the first decision in a block of decisions cast by voter on contest

#define EXPECT(condition, ...) \
    if (!(condition)) { \
        KJ_LOG(ERROR, __VA_ARGS__); \
    }

    // While we haven't processed all decisions in the index, and we haven't moved into decisions on the next contest
    while (begin != index.end() && begin->contestId == contestId) {
        auto voter = begin->voter;
        auto stake = voter(vdb.db()).balance;
        // Find the end of the block of decisions by this voter on this contest
        auto end = index.upper_bound(boost::make_tuple(contestId, voter));
        // Point begin at the next block of decisions, which prepares it for the next iteration of the loop
        begin = end;

        // end points to the first decision in the next block. Decrement it to point to the last decision in the
        // current block. It should be safe to blindly decrement this, since we got the voter from a decision, so it's
        // guaranteed there's at least one decision with the specified voter.
        --end;
        const auto& opinions = end->opinions;

        if (opinions.size() == 0 || opinions.begin()->second == 0)
            // Null decision; there's nothing to tally. Move on to the next voter.
            continue;
        EXPECT(opinions.size() == 1, "Only single-opinion decisions are currently supported",
               fc::json::to_pretty_string(opinions))

        auto opinionIndex = opinions.begin()->first;
        auto opinion = opinions.begin()->second;
        EXPECT(opinion == 1, "Only opinions of 1 are currently supported.", opinion);

        Results::key_type candidate;
        if (opinionIndex < contestantCount) {
            // Normal contestant; just take his index
            candidate = opinionIndex;
        } else {
            // Write-in; look up his name
            auto writeInIndex = opinionIndex - contestantCount;
            EXPECT(writeInIndex < end->writeIns.size(), "Decision references a nonexistent write-in");
            candidate = end->writeIns[writeInIndex].first;
        }

        // Add the voter's stake to the tally for the voter's chosen candidate
        results[candidate] += stake;
    }

#undef EXPECT

    return results;
}

void LiveContestResultsServer::populateResults(capnp::List<ContestResults::TalliedOpinion>::Builder resultsBuilder,
                                           Results results) {
    unsigned index = 0;
    for (const auto& result : results) {
        auto resultBuilder = resultsBuilder[index++];
        resultBuilder.setTally(result.second.value);
        if (result.first.type() == typeid(int32_t))
            resultBuilder.getContestant().setContestant(boost::get<int32_t>(result.first));
        else
            resultBuilder.getContestant().setWriteIn(boost::get<std::string>(result.first));
    }
}

} // namespace swv


Timeoutable::Timeoutable(int time) :
   timeouted(false)
{
   this->timer.setInterval(time);
   this->timer.setSingleShot(true);
}

/**
  * D-LAN - A decentralized LAN file sharing software.
  *
  */

#include <Common/Timeoutable.h>
using namespace Common;

/**
  * @param time [ms]
  */

bool Timeoutable::isTimedout() const
{
   return this->timeouted;
}

void Timeoutable::startTimer()
{
   if (!this->timer.isActive())
      connect(&this->timer, &QTimer::timeout, this, &Timeoutable::timeoutSlot);

   this->timer.start();
}

void Timeoutable::stopTimer()
{
   disconnect(&this->timer, &QTimer::timeout, this, &Timeoutable::timeoutSlot);
   this->timer.stop();
}

void Timeoutable::timeoutSlot()
{
   this->timeouted = true;
   emit timeout();
}