<commit_before>/*
 * This file is part of accounts-ui
 *
 * Copyright (C) 2009-2010 Nokia Corporation.
 *
 * Contact: Alberto Mardegan <alberto.mardegan@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 */

//project
#include "credentialwidget.h"
#include "genericaccountsetupform.h"
#include "genericaccountsetupformview.h"
#include "common.h"

//M
#include <MLayout>
#include <MLinearLayoutPolicy>
#include <MGridLayoutPolicy>
#include <MLocale>
#include <MButton>
#include <MTextEdit>
#include <MInfoBanner>
#include <MBasicListItem>
#include <MSeparator>
#include <MLabel>
#include <MProgressIndicator>
#include <MImageWidget>

//Qt
#include <QDebug>
#include <QDesktopServices>
#include <QUrl>
#include <QTimer>

const int BinaryTextVariantSeparator = 0x9c;

class GenericAccountSetupFormListItem: public MBasicListItem
{
public:
    GenericAccountSetupFormListItem(QGraphicsWidget *parent)
            : MBasicListItem(MBasicListItem::IconWithTitle, parent)
    {
        setStyleName("CommonBasicListItemInverted");
        titleLabelWidget()->setStyleName("GenericAccountSetupFormListItemStyle");
        setEnabled(false);
    }

    ~GenericAccountSetupFormListItem()
    {}
};

class GenericAccountSetupFormViewPrivate
{
public:
    GenericAccountSetupFormViewPrivate(GenericAccountSetupFormView *publicObject)
        : widgetModel(0),
          isInDomDocumentUpdate(false),
          q_ptr(publicObject)
    {
        controller = NULL;
        mainLayoutPolicy = NULL;
        mainLayout = NULL;
        separator = NULL;
        descriptionLabel = NULL;
        providerInfoItem = NULL;
        questionLabel = NULL;
        subscribeLabel = NULL;
        progressIndicator = NULL;
        connectingLabel = NULL;
        stopButton = NULL;
        widgetModel = NULL;
        credentialWidget = NULL;

        registerNewLink = QString();
        authDomainSeparator = QString();
        authDomainDefault = QString();
    }

    ~GenericAccountSetupFormViewPrivate()
    {}

    void createUiFromXml(const QDomDocument &providerAccountDocument);
    void showCredentialWidgetAndHideProgress();
    void hideCredentialWidgetAndShowProgress();

public:
    GenericAccountSetupForm *controller;
    MLinearLayoutPolicy *mainLayoutPolicy;
    MLayout *mainLayout;
    MSeparator *separator;
    MLabel *descriptionLabel;
    GenericAccountSetupFormListItem *providerInfoItem;
    CredentialWidgetModel *widgetModel;
    CredentialWidget *credentialWidget;
    MLabel *questionLabel;
    MLabel *subscribeLabel;
    MProgressIndicator *progressIndicator;
    MLabel *connectingLabel;
    MButton *stopButton;

    QMap<MWidget*, QDomElement> formWidgetDomElementMap;
    QDomDocument providerAccountDocument;
    bool isInDomDocumentUpdate;
    QString registerNewLink;
    QString authDomainSeparator;
    QString authDomainDefault;

protected:
    Q_DECLARE_PUBLIC(GenericAccountSetupFormView);
    GenericAccountSetupFormView *q_ptr;
};

void GenericAccountSetupFormViewPrivate::showCredentialWidgetAndHideProgress()
{
    if (mainLayoutPolicy) {
        for (int i = mainLayoutPolicy->count() - 1; i >= 0; i--)
            mainLayoutPolicy->removeAt(i);
    }

    if (mainLayout) {
        for (int i = mainLayout->count() - 1; i >= 0; i--)
            mainLayout->removeAt(i);
    }

    if (mainLayoutPolicy) {
        delete mainLayoutPolicy;
        mainLayoutPolicy = NULL;
    }

    if (connectingLabel) {
        delete connectingLabel;
        connectingLabel = NULL;
    }

    if (stopButton) {
        delete stopButton;
        stopButton = NULL;
    }

    mainLayoutPolicy = new MLinearLayoutPolicy(mainLayout, Qt::Vertical);

    mainLayoutPolicy->addItem(providerInfoItem, Qt::AlignTop);
    mainLayoutPolicy->addItem(descriptionLabel, Qt::AlignTop);
    mainLayoutPolicy->addItem(separator, Qt::AlignTop);
    mainLayoutPolicy->addItem(credentialWidget, Qt::AlignTop);
    mainLayoutPolicy->addStretch();
    mainLayoutPolicy->addItem(questionLabel, Qt::AlignCenter | Qt::AlignBottom);
    mainLayoutPolicy->addItem(subscribeLabel, Qt::AlignCenter | Qt::AlignBottom);
}

void GenericAccountSetupFormViewPrivate::hideCredentialWidgetAndShowProgress()
{
    if (mainLayoutPolicy) {
        for (int i = mainLayoutPolicy->count() - 1; i >= 0; i--)
            mainLayoutPolicy->removeAt(i);
    }

    if (mainLayout) {
        for (int i = mainLayout->count() - 1; i >= 0; i--)
            mainLayout->removeAt(i);
    }

    if (mainLayoutPolicy) {
        delete mainLayoutPolicy;
        mainLayoutPolicy = NULL;
    }

    mainLayoutPolicy = new MLinearLayoutPolicy(mainLayout, Qt::Vertical);

    mainLayoutPolicy->addItem(providerInfoItem, Qt::AlignTop);
    mainLayoutPolicy->addItem(descriptionLabel, Qt::AlignTop);
    mainLayoutPolicy->addItem(separator, Qt::AlignTop);
    progressIndicator = new MProgressIndicator(NULL, MProgressIndicator::spinnerType);
    progressIndicator->setUnknownDuration(true);
    progressIndicator->setStyleName("CommonLargeSpinnerInverted");

    //% "Connecting"
    connectingLabel = new MLabel(qtTrId("qtn_acc_connecting"));
    connectingLabel->setStyleName("ConnectingLabel");
    connectingLabel->setObjectName("wgGenericAccountSetupFormViewLabel");
    connectingLabel->setAlignment(Qt::AlignCenter);

    //% "STOP"
    stopButton = new MButton(qtTrId("qtn_comm_stop"));
    stopButton->setStyleName("CommonSingleButtonInverted");
    stopButton->setObjectName("wgGenericAccountSetupFormViewButton");
    QObject::connect(stopButton, SIGNAL(clicked()),
                     controller, SIGNAL(stopButtonPressed()));

    mainLayoutPolicy->addStretch();
    mainLayoutPolicy->addStretch(10);
    mainLayoutPolicy->addItem(progressIndicator, Qt::AlignCenter);
    mainLayoutPolicy->addStretch(2);
    mainLayoutPolicy->addItem(connectingLabel, Qt::AlignCenter);
    mainLayoutPolicy->addStretch(2);
    mainLayoutPolicy->addItem(stopButton, Qt::AlignCenter);
    mainLayoutPolicy->addStretch();
    mainLayoutPolicy->addStretch(10);
}

void GenericAccountSetupFormViewPrivate::createUiFromXml(const QDomDocument &aProviderAccountDocument)
{
    Q_Q(GenericAccountSetupFormView);
    MLocale locale;
    locale.installTrCatalog("signon-ui");
    MLocale::setDefault(locale);

    // xml file that describes the ui elements for the provider
    providerAccountDocument = aProviderAccountDocument;
    QDomElement root = aProviderAccountDocument.documentElement();
    QDomElement descriptionElement = root.firstChildElement("description");
    QDomElement providerIcon = root.firstChildElement("icon");
    QDomElement catalog = root.firstChildElement("translations");
    QDomElement signUpLink = root.firstChildElement("sign-up-link");

    if (!catalog.text().isEmpty()) {
        MLocale locale;
        locale.installTrCatalog(catalog.text());
        MLocale::setDefault(locale);
    }
    QString providerName = qtTrId(root.firstChildElement("name").text().toLatin1());
    if (q->model() != NULL) {
        q->model()->setProviderName(providerName);
    }
    QString descriptionText = descriptionElement.text();
    QString providerIconId = providerIcon.text();
    registerNewLink = signUpLink.text();

    QDomElement node = root.firstChildElement("account-setup").firstChildElement();
    while (!node.isNull()) {
        if (node.tagName() == "authdomain") {
            /* we select the first occurrence*/
            authDomainSeparator = node.attribute("separator");
            authDomainDefault = node.attribute("default_domain");
            break;
        }
        node = node.nextSiblingElement();
    }

    // Provider info widgets
    providerInfoItem = new GenericAccountSetupFormListItem(controller);
    providerInfoItem->setObjectName("wgGenericAccountSetupProviderInfoTitle");
    providerInfoItem->setTitle(providerName);
    providerInfoItem->imageWidget()->setImage(providerIconId);

    descriptionLabel = new MLabel(qtTrId(descriptionText.toLatin1()));
    descriptionLabel->setWordWrap(true);
    descriptionLabel->setWrapMode(QTextOption::WordWrap);
    descriptionLabel->setStyleName("CommonBodyTextInverted");

    // Credentials widget
    if (widgetModel) {
        delete widgetModel;
        widgetModel = NULL;
    }

    separator = new MSeparator();
    separator->setOrientation(Qt::Horizontal);
    separator->setStyleName("CommonItemDividerInverted");

    widgetModel = new CredentialWidgetModel();
    widgetModel->setDialogsVisabilityConfig(CredentialWidgetModel::LoginDialogVisible);
    widgetModel->setSignInButtonVisible(true);

    QObject::connect(widgetModel, SIGNAL(signInClicked()), q_ptr , SLOT(signIn()));
    QObject::connect(widgetModel, SIGNAL(modified(QList<const char*>)),
                     q_ptr, SLOT(updateModel(QList<const char*>)));

    credentialWidget = new CredentialWidget(widgetModel);
    if (!authDomainSeparator.isEmpty() || !authDomainDefault.isEmpty())
        credentialWidget->setUsername(authDomainSeparator + qtTrId(authDomainDefault.toLatin1()));

    // add the widgets to the layout
    mainLayoutPolicy->addItem(providerInfoItem);
    mainLayoutPolicy->addItem(descriptionLabel);
    mainLayoutPolicy->addItem(separator);
    mainLayoutPolicy->addItem(credentialWidget);
    mainLayoutPolicy->addStretch(3);

    if (!registerNewLink.isEmpty()) {

        //% "Don't have a %1 account yet?"
        questionLabel = new MLabel(qtTrId("qtn_acc_login_new_to_x").arg(providerName));
        questionLabel->setStyleName("CommonBodyTextInverted");
        questionLabel->setAlignment(Qt::AlignCenter);
        questionLabel->setWordWrap(true);
        questionLabel->setWrapMode(QTextOption::WordWrap);
        questionLabel->setObjectName("AccountsPrimaryInfoLabel");

        //% "Get one here"
        QString link("<a href=\"%1\"> " + qtTrId("qtn_acc_login_register_here") + "! </a>");
        /* fetch the first lenght variant as qt doesnt provide
            support for length variants for rich text */
        link = link.left(link.indexOf(QChar(BinaryTextVariantSeparator)));
        subscribeLabel = new MLabel(link.arg(registerNewLink));
        subscribeLabel->setTextFormat(Qt::RichText);
        subscribeLabel->setAlignment(Qt::AlignCenter);
        subscribeLabel->setObjectName("AccountsSecondaryInfoLabel");
        QObject::connect(subscribeLabel, SIGNAL(linkActivated(QString)),
                              q_ptr, SLOT(registerNew()));

        mainLayoutPolicy->addItem(questionLabel, Qt::AlignCenter);
        mainLayoutPolicy->addItem(subscribeLabel, Qt::AlignCenter);
    }
}

GenericAccountSetupFormView::GenericAccountSetupFormView(GenericAccountSetupForm *controller)
    : MWidgetView(controller)
    , d_ptr(new GenericAccountSetupFormViewPrivate(this))
{
    Q_ASSERT(controller);
    Q_D(GenericAccountSetupFormView);
    d->controller = controller;

    // layouts
    d->mainLayout = new MLayout();
    d->mainLayoutPolicy = new MLinearLayoutPolicy(d->mainLayout, Qt::Vertical);

    controller->setLayout(d->mainLayout);
}

GenericAccountSetupFormView::~GenericAccountSetupFormView()
{
    delete d_ptr;
}

void GenericAccountSetupFormView::updateDomDocument()
{
    qDebug()<<__PRETTY_FUNCTION__;
    Q_D(GenericAccountSetupFormView);

    Q_ASSERT(qobject_cast<MWidget*>(sender()));
    MWidget *formElement = qobject_cast<MWidget*>(sender());

    QDomElement domElement = d->formWidgetDomElementMap.value(formElement);

    if (qobject_cast<MTextEdit*>(sender())) {
        MTextEdit *textEdit = qobject_cast<MTextEdit*>(sender());
        domElement.setAttribute("value", textEdit->text());
    }

    if (qobject_cast<MButton*>(sender())) {
        MButton *button = qobject_cast<MButton*>(sender());
        button->setStyleName("button");
        domElement.setAttribute("value", QVariant(button->isChecked()).toString());
    }

    d->isInDomDocumentUpdate = true;

    // save the updated dom document back to the model
    model()->setProviderAccountDocumentAsString(d->providerAccountDocument.toString());
    d->isInDomDocumentUpdate = false;
}

void GenericAccountSetupFormView::updateData(const QList<const char*> &modifications)
{
    Q_D(GenericAccountSetupFormView);

    MWidgetView::updateData(modifications);

    foreach(const char *member, modifications) {
        if (!qstrcmp(member, "providerAccountDocumentAsString") &&
            d->isInDomDocumentUpdate == false) {
            QDomDocument providerAccountDocument;
            QString errorStr;
            int errorLine;
            int errorColumn;

            if (!providerAccountDocument.setContent(
                 model()->providerAccountDocumentAsString(),
                 true, &errorStr, &errorLine, &errorColumn)) {
                 Q_ASSERT_X(false, "DOM reading of provider account document",
                                  QString("Parse error at line %1, column %2:\n%3")
                                  .arg(errorLine)
                                  .arg(errorColumn)
                                  .arg(errorStr).toAscii());
            }
            d->createUiFromXml(providerAccountDocument);
        } else if (!qstrcmp(member, "credentialWidgetEnabled")) {
            if (model()->credentialWidgetEnabled()) {
                d->showCredentialWidgetAndHideProgress();
            } else {
                d->hideCredentialWidgetAndShowProgress();
            }
        }
    }
}

void GenericAccountSetupFormView::setupModel()
{
    MWidgetView::setupModel();
}

void GenericAccountSetupFormView::signIn()
{
    Q_D(GenericAccountSetupFormView);

    if (d->widgetModel->username().isEmpty()) {
        //% "Fill in username"
        showInfoBanner(qtTrId("qtn_acc_fill_in_username_infobanner"));
        return;
    }

    if (d->widgetModel->password().isEmpty()) {
        //% "Fill in password"
        showInfoBanner(qtTrId("qtn_acc_fill_in_password_infobanner"));
        return;
    }

    if (!d->authDomainSeparator.isEmpty() &&
        !d->widgetModel->username().contains(d->authDomainSeparator)) {
        //% "Fill in username@example.com"
        showInfoBanner(qtTrId("qtn_acc_fill_in_username_with_domain_infobanner"));
        return;
    }

    model()->setRememberMe(d->widgetModel->checkboxPressed());
    model()->setUsername(d->widgetModel->username());
    model()->setPassword(d->widgetModel->password());

    d->controller->validateCredentials();
}

void GenericAccountSetupFormView::updateModel(QList<const char*> modifications)
{
    Q_D(GenericAccountSetupFormView);

    foreach(const char *member, modifications) {
        if (!qstrcmp(member, "username")) {
            model()->setUsername(d->widgetModel->username());
        } else if (!qstrcmp(member, "password")) {
            model()->setPassword(d->widgetModel->password());
        }
     }
}

void GenericAccountSetupFormView::registerNew()
{
    Q_D(GenericAccountSetupFormView);
    if (!QDesktopServices::openUrl(QUrl(d->registerNewLink)))
    qWarning() << Q_FUNC_INFO << "Unable to open web browser";
}

// bind view and controller together
M_REGISTER_VIEW_NEW(GenericAccountSetupFormView, GenericAccountSetupForm)
<commit_msg>Fixing: 204977 - Duplicate account creation Dialog not shown if duplicate account is created<commit_after>/*
 * This file is part of accounts-ui
 *
 * Copyright (C) 2009-2010 Nokia Corporation.
 *
 * Contact: Alberto Mardegan <alberto.mardegan@nokia.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 */

//project
#include "credentialwidget.h"
#include "genericaccountsetupform.h"
#include "genericaccountsetupformview.h"
#include "common.h"
#include "accountsmanagersingleton.h"
#include "provider-plugin-process.h"

//M
#include <MLayout>
#include <MLinearLayoutPolicy>
#include <MGridLayoutPolicy>
#include <MLocale>
#include <MButton>
#include <MTextEdit>
#include <MInfoBanner>
#include <MBasicListItem>
#include <MSeparator>
#include <MLabel>
#include <MProgressIndicator>
#include <MImageWidget>
#include <MMessageBox>

//Qt
#include <QDebug>
#include <QDesktopServices>
#include <QUrl>
#include <QTimer>

using namespace Accounts;
const int BinaryTextVariantSeparator = 0x9c;

class GenericAccountSetupFormListItem: public MBasicListItem
{
public:
    GenericAccountSetupFormListItem(QGraphicsWidget *parent)
            : MBasicListItem(MBasicListItem::IconWithTitle, parent)
    {
        setStyleName("CommonBasicListItemInverted");
        titleLabelWidget()->setStyleName("GenericAccountSetupFormListItemStyle");
        setEnabled(false);
    }

    ~GenericAccountSetupFormListItem()
    {}
};

class GenericAccountSetupFormViewPrivate
{
public:
    GenericAccountSetupFormViewPrivate(GenericAccountSetupFormView *publicObject)
        : widgetModel(0),
          isInDomDocumentUpdate(false),
          q_ptr(publicObject)
    {
        controller = NULL;
        mainLayoutPolicy = NULL;
        mainLayout = NULL;
        separator = NULL;
        descriptionLabel = NULL;
        providerInfoItem = NULL;
        questionLabel = NULL;
        subscribeLabel = NULL;
        progressIndicator = NULL;
        connectingLabel = NULL;
        stopButton = NULL;
        widgetModel = NULL;
        credentialWidget = NULL;

        registerNewLink = QString();
        authDomainSeparator = QString();
        authDomainDefault = QString();
        provider = QString();
    }

    ~GenericAccountSetupFormViewPrivate()
    {}

    void createUiFromXml(const QDomDocument &providerAccountDocument);
    void showCredentialWidgetAndHideProgress();
    void hideCredentialWidgetAndShowProgress();

public:
    GenericAccountSetupForm *controller;
    MLinearLayoutPolicy *mainLayoutPolicy;
    MLayout *mainLayout;
    MSeparator *separator;
    MLabel *descriptionLabel;
    GenericAccountSetupFormListItem *providerInfoItem;
    CredentialWidgetModel *widgetModel;
    CredentialWidget *credentialWidget;
    MLabel *questionLabel;
    MLabel *subscribeLabel;
    MProgressIndicator *progressIndicator;
    MLabel *connectingLabel;
    MButton *stopButton;

    QMap<MWidget*, QDomElement> formWidgetDomElementMap;
    QDomDocument providerAccountDocument;
    bool isInDomDocumentUpdate;
    QString registerNewLink;
    QString authDomainSeparator;
    QString authDomainDefault;
    QString provider;

protected:
    Q_DECLARE_PUBLIC(GenericAccountSetupFormView);
    GenericAccountSetupFormView *q_ptr;
};

void GenericAccountSetupFormViewPrivate::showCredentialWidgetAndHideProgress()
{
    if (mainLayoutPolicy) {
        for (int i = mainLayoutPolicy->count() - 1; i >= 0; i--)
            mainLayoutPolicy->removeAt(i);
    }

    if (mainLayout) {
        for (int i = mainLayout->count() - 1; i >= 0; i--)
            mainLayout->removeAt(i);
    }

    if (mainLayoutPolicy) {
        delete mainLayoutPolicy;
        mainLayoutPolicy = NULL;
    }

    if (connectingLabel) {
        delete connectingLabel;
        connectingLabel = NULL;
    }

    if (stopButton) {
        delete stopButton;
        stopButton = NULL;
    }

    mainLayoutPolicy = new MLinearLayoutPolicy(mainLayout, Qt::Vertical);

    mainLayoutPolicy->addItem(providerInfoItem, Qt::AlignTop);
    mainLayoutPolicy->addItem(descriptionLabel, Qt::AlignTop);
    mainLayoutPolicy->addItem(separator, Qt::AlignTop);
    mainLayoutPolicy->addItem(credentialWidget, Qt::AlignTop);
    mainLayoutPolicy->addStretch();
    mainLayoutPolicy->addItem(questionLabel, Qt::AlignCenter | Qt::AlignBottom);
    mainLayoutPolicy->addItem(subscribeLabel, Qt::AlignCenter | Qt::AlignBottom);
}

void GenericAccountSetupFormViewPrivate::hideCredentialWidgetAndShowProgress()
{
    if (mainLayoutPolicy) {
        for (int i = mainLayoutPolicy->count() - 1; i >= 0; i--)
            mainLayoutPolicy->removeAt(i);
    }

    if (mainLayout) {
        for (int i = mainLayout->count() - 1; i >= 0; i--)
            mainLayout->removeAt(i);
    }

    if (mainLayoutPolicy) {
        delete mainLayoutPolicy;
        mainLayoutPolicy = NULL;
    }

    mainLayoutPolicy = new MLinearLayoutPolicy(mainLayout, Qt::Vertical);

    mainLayoutPolicy->addItem(providerInfoItem, Qt::AlignTop);
    mainLayoutPolicy->addItem(descriptionLabel, Qt::AlignTop);
    mainLayoutPolicy->addItem(separator, Qt::AlignTop);
    progressIndicator = new MProgressIndicator(NULL, MProgressIndicator::spinnerType);
    progressIndicator->setUnknownDuration(true);
    progressIndicator->setStyleName("CommonLargeSpinnerInverted");

    //% "Connecting"
    connectingLabel = new MLabel(qtTrId("qtn_acc_connecting"));
    connectingLabel->setStyleName("ConnectingLabel");
    connectingLabel->setObjectName("wgGenericAccountSetupFormViewLabel");
    connectingLabel->setAlignment(Qt::AlignCenter);

    //% "STOP"
    stopButton = new MButton(qtTrId("qtn_comm_stop"));
    stopButton->setStyleName("CommonSingleButtonInverted");
    stopButton->setObjectName("wgGenericAccountSetupFormViewButton");
    QObject::connect(stopButton, SIGNAL(clicked()),
                     controller, SIGNAL(stopButtonPressed()));

    mainLayoutPolicy->addStretch();
    mainLayoutPolicy->addStretch(10);
    mainLayoutPolicy->addItem(progressIndicator, Qt::AlignCenter);
    mainLayoutPolicy->addStretch(2);
    mainLayoutPolicy->addItem(connectingLabel, Qt::AlignCenter);
    mainLayoutPolicy->addStretch(2);
    mainLayoutPolicy->addItem(stopButton, Qt::AlignCenter);
    mainLayoutPolicy->addStretch();
    mainLayoutPolicy->addStretch(10);
}

void GenericAccountSetupFormViewPrivate::createUiFromXml(const QDomDocument &aProviderAccountDocument)
{
    Q_Q(GenericAccountSetupFormView);
    MLocale locale;
    locale.installTrCatalog("signon-ui");
    MLocale::setDefault(locale);

    // xml file that describes the ui elements for the provider
    providerAccountDocument = aProviderAccountDocument;
    QDomElement root = aProviderAccountDocument.documentElement();
    QDomElement descriptionElement = root.firstChildElement("description");
    QDomElement providerIcon = root.firstChildElement("icon");
    QDomElement catalog = root.firstChildElement("translations");
    QDomElement signUpLink = root.firstChildElement("sign-up-link");
    provider = root.attribute("id");

    if (!catalog.text().isEmpty()) {
        MLocale locale;
        locale.installTrCatalog(catalog.text());
        MLocale::setDefault(locale);
    }
    QString providerName = qtTrId(root.firstChildElement("name").text().toLatin1());
    if (q->model() != NULL) {
        q->model()->setProviderName(providerName);
    }
    QString descriptionText = descriptionElement.text();
    QString providerIconId = providerIcon.text();
    registerNewLink = signUpLink.text();

    QDomElement node = root.firstChildElement("account-setup").firstChildElement();
    while (!node.isNull()) {
        if (node.tagName() == "authdomain") {
            /* we select the first occurrence*/
            authDomainSeparator = node.attribute("separator");
            authDomainDefault = node.attribute("default_domain");
            break;
        }
        node = node.nextSiblingElement();
    }

    // Provider info widgets
    providerInfoItem = new GenericAccountSetupFormListItem(controller);
    providerInfoItem->setObjectName("wgGenericAccountSetupProviderInfoTitle");
    providerInfoItem->setTitle(providerName);
    providerInfoItem->imageWidget()->setImage(providerIconId);

    descriptionLabel = new MLabel(qtTrId(descriptionText.toLatin1()));
    descriptionLabel->setWordWrap(true);
    descriptionLabel->setWrapMode(QTextOption::WordWrap);
    descriptionLabel->setStyleName("CommonBodyTextInverted");

    // Credentials widget
    if (widgetModel) {
        delete widgetModel;
        widgetModel = NULL;
    }

    separator = new MSeparator();
    separator->setOrientation(Qt::Horizontal);
    separator->setStyleName("CommonItemDividerInverted");

    widgetModel = new CredentialWidgetModel();
    widgetModel->setDialogsVisabilityConfig(CredentialWidgetModel::LoginDialogVisible);
    widgetModel->setSignInButtonVisible(true);

    QObject::connect(widgetModel, SIGNAL(signInClicked()), q_ptr , SLOT(signIn()));
    QObject::connect(widgetModel, SIGNAL(modified(QList<const char*>)),
                     q_ptr, SLOT(updateModel(QList<const char*>)));

    credentialWidget = new CredentialWidget(widgetModel);
    if (!authDomainSeparator.isEmpty() || !authDomainDefault.isEmpty())
        credentialWidget->setUsername(authDomainSeparator + qtTrId(authDomainDefault.toLatin1()));

    // add the widgets to the layout
    mainLayoutPolicy->addItem(providerInfoItem);
    mainLayoutPolicy->addItem(descriptionLabel);
    mainLayoutPolicy->addItem(separator);
    mainLayoutPolicy->addItem(credentialWidget);
    mainLayoutPolicy->addStretch(3);

    if (!registerNewLink.isEmpty()) {

        //% "Don't have a %1 account yet?"
        questionLabel = new MLabel(qtTrId("qtn_acc_login_new_to_x").arg(providerName));
        questionLabel->setStyleName("CommonBodyTextInverted");
        questionLabel->setAlignment(Qt::AlignCenter);
        questionLabel->setWordWrap(true);
        questionLabel->setWrapMode(QTextOption::WordWrap);
        questionLabel->setObjectName("AccountsPrimaryInfoLabel");

        //% "Get one here"
        QString link("<a href=\"%1\"> " + qtTrId("qtn_acc_login_register_here") + "! </a>");
        /* fetch the first lenght variant as qt doesnt provide
            support for length variants for rich text */
        link = link.left(link.indexOf(QChar(BinaryTextVariantSeparator)));
        subscribeLabel = new MLabel(link.arg(registerNewLink));
        subscribeLabel->setTextFormat(Qt::RichText);
        subscribeLabel->setAlignment(Qt::AlignCenter);
        subscribeLabel->setObjectName("AccountsSecondaryInfoLabel");
        QObject::connect(subscribeLabel, SIGNAL(linkActivated(QString)),
                              q_ptr, SLOT(registerNew()));

        mainLayoutPolicy->addItem(questionLabel, Qt::AlignCenter);
        mainLayoutPolicy->addItem(subscribeLabel, Qt::AlignCenter);
    }
}

GenericAccountSetupFormView::GenericAccountSetupFormView(GenericAccountSetupForm *controller)
    : MWidgetView(controller)
    , d_ptr(new GenericAccountSetupFormViewPrivate(this))
{
    Q_ASSERT(controller);
    Q_D(GenericAccountSetupFormView);
    d->controller = controller;

    // layouts
    d->mainLayout = new MLayout();
    d->mainLayoutPolicy = new MLinearLayoutPolicy(d->mainLayout, Qt::Vertical);

    controller->setLayout(d->mainLayout);
}

GenericAccountSetupFormView::~GenericAccountSetupFormView()
{
    delete d_ptr;
}

void GenericAccountSetupFormView::updateDomDocument()
{
    qDebug()<<__PRETTY_FUNCTION__;
    Q_D(GenericAccountSetupFormView);

    Q_ASSERT(qobject_cast<MWidget*>(sender()));
    MWidget *formElement = qobject_cast<MWidget*>(sender());

    QDomElement domElement = d->formWidgetDomElementMap.value(formElement);

    if (qobject_cast<MTextEdit*>(sender())) {
        MTextEdit *textEdit = qobject_cast<MTextEdit*>(sender());
        domElement.setAttribute("value", textEdit->text());
    }

    if (qobject_cast<MButton*>(sender())) {
        MButton *button = qobject_cast<MButton*>(sender());
        button->setStyleName("button");
        domElement.setAttribute("value", QVariant(button->isChecked()).toString());
    }

    d->isInDomDocumentUpdate = true;

    // save the updated dom document back to the model
    model()->setProviderAccountDocumentAsString(d->providerAccountDocument.toString());
    d->isInDomDocumentUpdate = false;
}

void GenericAccountSetupFormView::updateData(const QList<const char*> &modifications)
{
    Q_D(GenericAccountSetupFormView);

    MWidgetView::updateData(modifications);

    foreach(const char *member, modifications) {
        if (!qstrcmp(member, "providerAccountDocumentAsString") &&
            d->isInDomDocumentUpdate == false) {
            QDomDocument providerAccountDocument;
            QString errorStr;
            int errorLine;
            int errorColumn;

            if (!providerAccountDocument.setContent(
                 model()->providerAccountDocumentAsString(),
                 true, &errorStr, &errorLine, &errorColumn)) {
                 Q_ASSERT_X(false, "DOM reading of provider account document",
                                  QString("Parse error at line %1, column %2:\n%3")
                                  .arg(errorLine)
                                  .arg(errorColumn)
                                  .arg(errorStr).toAscii());
            }
            d->createUiFromXml(providerAccountDocument);
        } else if (!qstrcmp(member, "credentialWidgetEnabled")) {
            if (model()->credentialWidgetEnabled()) {
                d->showCredentialWidgetAndHideProgress();
            } else {
                d->hideCredentialWidgetAndShowProgress();
            }
        }
    }
}

void GenericAccountSetupFormView::setupModel()
{
    MWidgetView::setupModel();
}

void GenericAccountSetupFormView::signIn()
{
    Q_D(GenericAccountSetupFormView);

    if (d->widgetModel->username().isEmpty()) {
        //% "Fill in username"
        showInfoBanner(qtTrId("qtn_acc_fill_in_username_infobanner"));
        return;
    }

    if (d->widgetModel->password().isEmpty()) {
        //% "Fill in password"
        showInfoBanner(qtTrId("qtn_acc_fill_in_password_infobanner"));
        return;
    }

    if (!d->authDomainSeparator.isEmpty() &&
        !d->widgetModel->username().contains(d->authDomainSeparator)) {
        //% "Fill in username@example.com"
        showInfoBanner(qtTrId("qtn_acc_fill_in_username_with_domain_infobanner"));
        return;
    }

    AccountIdList idList = AccountsManager::instance()->accountList();
    foreach (Accounts::AccountId id, idList) {
        Accounts::Account *account = AccountsManager::instance()->account(id);
        if ((d->widgetModel->username() == account->displayName()) &&
            (d->provider == account->providerName())) {
            MMessageBox queryBox(qtTrId("qtn_acc_account_exists"), qtTrId("qtn_acc_tune_it_in_accounts"), 0);
            MButton *continueButton = new MButton(qtTrId("qtn_comm_command_continue"));
            MButton *cancelButton = new MButton(qtTrId("qtn_comm_cancel"));
            queryBox.addButton(continueButton->model());
            queryBox.addButton(cancelButton->model());
            queryBox.exec();
            if (queryBox.clickedButton() == continueButton->model())
                ProviderPluginProcess::instance()->setReturnToAccountsList(true);
            else if (queryBox.clickedButton() == cancelButton->model())
                ProviderPluginProcess::instance()->quit();
        }
    }

    model()->setRememberMe(d->widgetModel->checkboxPressed());
    model()->setUsername(d->widgetModel->username());
    model()->setPassword(d->widgetModel->password());

    d->controller->validateCredentials();
}

void GenericAccountSetupFormView::updateModel(QList<const char*> modifications)
{
    Q_D(GenericAccountSetupFormView);

    foreach(const char *member, modifications) {
        if (!qstrcmp(member, "username")) {
            model()->setUsername(d->widgetModel->username());
        } else if (!qstrcmp(member, "password")) {
            model()->setPassword(d->widgetModel->password());
        }
     }
}

void GenericAccountSetupFormView::registerNew()
{
    Q_D(GenericAccountSetupFormView);
    if (!QDesktopServices::openUrl(QUrl(d->registerNewLink)))
    qWarning() << Q_FUNC_INFO << "Unable to open web browser";
}

// bind view and controller together
M_REGISTER_VIEW_NEW(GenericAccountSetupFormView, GenericAccountSetupForm)
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2016 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
////////////////////////////////////////////////////////////////////////////////

#include "EnvironmentFeature.h"
#include "ApplicationFeatures/MaxMapCountFeature.h"
#include "Basics/process-utils.h"
#include "Basics/FileUtils.h"
#include "Basics/StringUtils.h"
#include "Logger/Logger.h"
#include "RocksDBEngine/RocksDBEngine.h"
#include "StorageEngine/EngineSelectorFeature.h"

#ifdef __linux__
#include <sys/sysinfo.h>
#endif

using namespace arangodb;
using namespace arangodb::basics;

EnvironmentFeature::EnvironmentFeature(
    application_features::ApplicationServer* server)
    : ApplicationFeature(server, "Environment") {
  setOptional(false);
  requiresElevatedPrivileges(false);
  startsAfter("Greetings");
  startsAfter("Logger");
  startsAfter("MaxMapCount");
}

void EnvironmentFeature::prepare() {
  if (sizeof(void*) == 4) {
    // 32 bit build
    LOG_TOPIC(WARN, arangodb::Logger::MEMORY)
        << "this is a 32 bit build of ArangoDB. "
        << "it is recommended to run a 64 bit build instead because it can "
        << "address significantly bigger regions of memory";
  }

#ifdef __linux__
  // test local ipv4 port range
  try {
    std::string value =
        basics::FileUtils::slurp("/proc/sys/net/ipv4/ip_local_port_range");

    std::vector<std::string> parts = basics::StringUtils::split(value, '\t');
    if (parts.size() == 2) {
      uint64_t lower = basics::StringUtils::uint64(parts[0]);
      uint64_t upper = basics::StringUtils::uint64(parts[1]);

      if (lower > upper || (upper - lower) < 16384) {
        LOG_TOPIC(WARN, arangodb::Logger::COMMUNICATION)
            << "local port range for ipv4/ipv6 ports is " << lower << " - " << upper
            << ", which does not look right. it is recommended to make at least 16K ports available";
        LOG_TOPIC(WARN, Logger::MEMORY) << "execute 'sudo bash -c \"echo -e \\\"32768\\t60999\\\" > "
                                           "/proc/sys/net/ipv4/ip_local_port_range\"' or use an even bigger port range";
      }
    }
  } catch (...) {
    // file not found or values not convertible into integers
  }

  // test value tcp_tw_recycle
  // https://vincent.bernat.im/en/blog/2014-tcp-time-wait-state-linux
  // https://stackoverflow.com/questions/8893888/dropping-of-connections-with-tcp-tw-recycle
  try {
    std::string value =
        basics::FileUtils::slurp("/proc/sys/net/ipv4/tcp_tw_recycle");
    uint64_t v = basics::StringUtils::uint64(value);
    if (v != 0) {
      LOG_TOPIC(WARN, Logger::COMMUNICATION)
          << "/proc/sys/net/ipv4/tcp_tw_recycle is enabled (" << v << ")"
          << "'. This can lead to all sorts of \"random\" network problems. "
          << "It is advised to leave it disabled (should be kernel default)";
      LOG_TOPIC(WARN, Logger::COMMUNICATION) << "execute 'sudo bash -c \"echo 0 > "
                                         "/proc/sys/net/ipv4/tcp_tw_recycle\"'";
    }
  } catch (...) {
    // file not found or value not convertible into integer
  }

#ifdef __GLIBC__
  // test presence of environment variable GLIBCXX_FORCE_NEW
  char const* v = getenv("GLIBCXX_FORCE_NEW");

  if (v == nullptr) {
    // environment variable not set
    LOG_TOPIC(WARN, arangodb::Logger::MEMORY)
        << "environment variable GLIBCXX_FORCE_NEW' is not set. "
        << "it is recommended to set it to some value to avoid unnecessary memory pooling in glibc++";
    LOG_TOPIC(WARN, arangodb::Logger::MEMORY)
        << "execute 'export GLIBCXX_FORCE_NEW=1'";
  }
#endif

  // test max_map_count
  if (MaxMapCountFeature::needsChecking()) {
    uint64_t actual = MaxMapCountFeature::actualMaxMappings();
    uint64_t expected = MaxMapCountFeature::minimumExpectedMaxMappings();

    if (actual < expected) {
      LOG_TOPIC(WARN, arangodb::Logger::MEMORY)
          << "maximum number of memory mappings per process is " << actual
          << ", which seems too low. it is recommended to set it to at least " << expected;
      LOG_TOPIC(WARN, Logger::MEMORY) << "execute 'sudo sysctl -w \"vm.max_map_count=" << expected << "\"'";
    }
  }

  // test zone_reclaim_mode
  try {
    std::string value =
        basics::FileUtils::slurp("/proc/sys/vm/zone_reclaim_mode");
    uint64_t v = basics::StringUtils::uint64(value);
    if (v != 0) {
      // from https://www.kernel.org/doc/Documentation/sysctl/vm.txt:
      //
      //    This is value ORed together of
      //    1 = Zone reclaim on
      //    2 = Zone reclaim writes dirty pages out
      //    4 = Zone reclaim swaps pages
      //
      // https://www.poempelfox.de/blog/2010/03/19/
      LOG_TOPIC(WARN, Logger::PERFORMANCE)
          << "/proc/sys/vm/zone_reclaim_mode is set to '" << v
          << "'. It is recommended to set it to a value of 0";
      LOG_TOPIC(WARN, Logger::PERFORMANCE)
          << "execute 'sudo bash -c \"echo 0 > "
             "/proc/sys/vm/zone_reclaim_mode\"'";
    }
  } catch (...) {
    // file not found or value not convertible into integer
  }

  bool showHuge = false;
  std::vector<std::string> paths = {
      "/sys/kernel/mm/transparent_hugepage/enabled",
      "/sys/kernel/mm/transparent_hugepage/defrag"};

  for (auto file : paths) {
    try {
      std::string value = basics::FileUtils::slurp(file);
      size_t start = value.find('[');
      size_t end = value.find(']');

      if (start != std::string::npos && end != std::string::npos &&
          start < end && end - start >= 4) {
        value = value.substr(start + 1, end - start - 1);
        if (value == "always") {
          LOG_TOPIC(WARN, Logger::MEMORY)
              << file << " is set to '" << value
              << "'. It is recommended to set it to a value of 'never' "
                 "or 'madvise'";
          showHuge = true;
        }
      }
    } catch (...) {
      // file not found
    }
  }

  if (showHuge) {
    for (auto file : paths) {
      LOG_TOPIC(WARN, Logger::MEMORY)
          << "execute 'sudo bash -c \"echo madvise > " << file << "\"'";
    }
  }

  bool numa = FileUtils::exists("/sys/devices/system/node/node1");

  if (numa) {
    try {
      std::string value = basics::FileUtils::slurp("/proc/self/numa_maps");
      auto values = basics::StringUtils::split(value, '\n', '\0');

      if (!values.empty()) {
        auto first = values[0];
        auto where = first.find(' ');

        if (where != std::string::npos &&
            !StringUtils::isPrefix(first.substr(where), " interleave")) {
          LOG_TOPIC(WARN, Logger::MEMORY)
              << "It is recommended to set NUMA to interleaved.";
          LOG_TOPIC(WARN, Logger::MEMORY)
              << "put 'numactl --interleave=all' in front of your command";
        }
      }
    } catch (...) {
      // file not found
    }
  }

#endif
}

void EnvironmentFeature::start() {
#ifdef __linux__
  try {
    std::string value =
        basics::FileUtils::slurp("/proc/sys/vm/overcommit_memory");
    uint64_t v = basics::StringUtils::uint64(value);
    // from https://www.kernel.org/doc/Documentation/sysctl/vm.txt:
    //
    //   When this flag is 0, the kernel attempts to estimate the amount
    //   of free memory left when userspace requests more memory.
    //   When this flag is 1, the kernel pretends there is always enough
    //   memory until it actually runs out.
    //   When this flag is 2, the kernel uses a "never overcommit"
    //   policy that attempts to prevent any overcommit of memory.
    std::string ratio =
        basics::FileUtils::slurp("/proc/sys/vm/overcommit_ratio");
    uint64_t r = basics::StringUtils::uint64(ratio);
    // from https://www.kernel.org/doc/Documentation/sysctl/vm.txt:
    //
    //  When overcommit_memory is set to 2, the committed address
    //  space is not permitted to exceed swap plus this percentage
    //  of physical RAM.

    if (EngineSelectorFeature::engineName() == RocksDBEngine::EngineName) {
      if (v != 2) {
        LOG_TOPIC(WARN, Logger::MEMORY)
          << "/proc/sys/vm/overcommit_memory is set to '" << v
          << "'. It is recommended to set it to a value of 2";
        LOG_TOPIC(WARN, Logger::MEMORY) << "execute 'sudo bash -c \"echo 2 > "
                                        << "/proc/sys/vm/overcommit_memory\"'";
      }
    } else {
      if (v == 1) {
        LOG_TOPIC(WARN, Logger::MEMORY)
          << "/proc/sys/vm/overcommit_memory is set to '" << v
          << "'. It is recommended to set it to a value of 0 or 2";
        LOG_TOPIC(WARN, Logger::MEMORY) << "execute 'sudo bash -c \"echo 2 > "
                                        << "/proc/sys/vm/overcommit_memory\"'";
      }
    }
    if (v == 2) {
      struct sysinfo info;
      int res = sysinfo(&info);
      if (res == 0) {
        double swapSpace = static_cast<double>(info.totalswap);
        double ram = static_cast<double>(TRI_PhysicalMemory);
        double rr = (ram >= swapSpace)
            ? 100.0 * ((ram - swapSpace) / ram)
            : 0.0;
        if (static_cast<double>(r) < 0.99 * rr) {
          LOG_TOPIC(WARN, Logger::MEMORY)
            << "/proc/sys/vm/overcommit_ratio is set to '" << r
            << "'. It is recommended to set it to at least '" << std::llround(rr)
            << "' (100 * (max(0, (RAM - Swap Space)) / RAM)) to utilize all "
            << "available RAM. Setting it to this value will minimize swap "
            << "usage, but may result in more out-of-memory errors, while "
            << "setting it to 100 will allow the system to use both all "
            << "available RAM and swap space.";
          LOG_TOPIC(WARN, Logger::MEMORY) << "execute 'sudo bash -c \"echo "
                                          << std::llround(rr) << " > "
                                          << "/proc/sys/vm/overcommit_ratio\"'";
        }
      }
    }
  } catch (...) {
    // file not found or value not convertible into integer
  }
#endif
}
<commit_msg>more startup environment checks (#3566)<commit_after>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2016 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
////////////////////////////////////////////////////////////////////////////////

#include "EnvironmentFeature.h"
#include "ApplicationFeatures/MaxMapCountFeature.h"
#include "Basics/process-utils.h"
#include "Basics/FileUtils.h"
#include "Basics/StringUtils.h"
#include "Logger/Logger.h"
#include "RocksDBEngine/RocksDBEngine.h"
#include "StorageEngine/EngineSelectorFeature.h"

#ifdef __linux__
#include <sys/sysinfo.h>
#endif

using namespace arangodb;
using namespace arangodb::basics;

EnvironmentFeature::EnvironmentFeature(
    application_features::ApplicationServer* server)
    : ApplicationFeature(server, "Environment") {
  setOptional(false);
  requiresElevatedPrivileges(false);
  startsAfter("Greetings");
  startsAfter("Logger");
  startsAfter("MaxMapCount");
}

void EnvironmentFeature::prepare() {
#ifdef __linux__
  try {
    if (basics::FileUtils::exists("/proc/version")) {
      std::string value = basics::StringUtils::trim(basics::FileUtils::slurp("/proc/version"));
      LOG_TOPIC(INFO, Logger::FIXME) << "detected operating system: " << value;
    }
  } catch (...) {
    // ignore any errors as the log output is just informational
  }
#endif

  if (sizeof(void*) == 4) {
    // 32 bit build
    LOG_TOPIC(WARN, arangodb::Logger::MEMORY)
        << "this is a 32 bit build of ArangoDB. "
        << "it is recommended to run a 64 bit build instead because it can "
        << "address significantly bigger regions of memory";
  }

#ifdef __linux__
  {
    char const* v = getenv("MALLOC_CONF");

    if (v != nullptr) {
      // report value of MALLOC_CONF environment variable
      LOG_TOPIC(WARN, arangodb::Logger::MEMORY)
          << "found custom MALLOC_CONF environment value '" << v << "'";
    }
  }

  // test local ipv6 support
  try {
    if (!basics::FileUtils::exists("/proc/net/if_inet6")) {
      LOG_TOPIC(INFO, arangodb::Logger::COMMUNICATION) << "IPv6 support seems to be disabled";
    }
  } catch (...) {
    // file not found
  }

  // test local ipv4 port range
  try {
    std::string value =
        basics::FileUtils::slurp("/proc/sys/net/ipv4/ip_local_port_range");

    std::vector<std::string> parts = basics::StringUtils::split(value, '\t');
    if (parts.size() == 2) {
      uint64_t lower = basics::StringUtils::uint64(parts[0]);
      uint64_t upper = basics::StringUtils::uint64(parts[1]);

      if (lower > upper || (upper - lower) < 16384) {
        LOG_TOPIC(WARN, arangodb::Logger::COMMUNICATION)
            << "local port range for ipv4/ipv6 ports is " << lower << " - " << upper
            << ", which does not look right. it is recommended to make at least 16K ports available";
        LOG_TOPIC(WARN, Logger::MEMORY) << "execute 'sudo bash -c \"echo -e \\\"32768\\t60999\\\" > "
                                           "/proc/sys/net/ipv4/ip_local_port_range\"' or use an even bigger port range";
      }
    }
  } catch (...) {
    // file not found or values not convertible into integers
  }

  // test value tcp_tw_recycle
  // https://vincent.bernat.im/en/blog/2014-tcp-time-wait-state-linux
  // https://stackoverflow.com/questions/8893888/dropping-of-connections-with-tcp-tw-recycle
  try {
    std::string value =
        basics::FileUtils::slurp("/proc/sys/net/ipv4/tcp_tw_recycle");
    uint64_t v = basics::StringUtils::uint64(value);
    if (v != 0) {
      LOG_TOPIC(WARN, Logger::COMMUNICATION)
          << "/proc/sys/net/ipv4/tcp_tw_recycle is enabled (" << v << ")"
          << "'. This can lead to all sorts of \"random\" network problems. "
          << "It is advised to leave it disabled (should be kernel default)";
      LOG_TOPIC(WARN, Logger::COMMUNICATION) << "execute 'sudo bash -c \"echo 0 > "
                                         "/proc/sys/net/ipv4/tcp_tw_recycle\"'";
    }
  } catch (...) {
    // file not found or value not convertible into integer
  }

#ifdef __GLIBC__
  {
    // test presence of environment variable GLIBCXX_FORCE_NEW
    char const* v = getenv("GLIBCXX_FORCE_NEW");

    if (v == nullptr) {
      // environment variable not set
      LOG_TOPIC(WARN, arangodb::Logger::MEMORY)
          << "environment variable GLIBCXX_FORCE_NEW' is not set. "
          << "it is recommended to set it to some value to avoid unnecessary memory pooling in glibc++";
      LOG_TOPIC(WARN, arangodb::Logger::MEMORY)
          << "execute 'export GLIBCXX_FORCE_NEW=1'";
    }
  }
#endif

  // test max_map_count
  if (MaxMapCountFeature::needsChecking()) {
    uint64_t actual = MaxMapCountFeature::actualMaxMappings();
    uint64_t expected = MaxMapCountFeature::minimumExpectedMaxMappings();

    if (actual < expected) {
      LOG_TOPIC(WARN, arangodb::Logger::MEMORY)
          << "maximum number of memory mappings per process is " << actual
          << ", which seems too low. it is recommended to set it to at least " << expected;
      LOG_TOPIC(WARN, Logger::MEMORY) << "execute 'sudo sysctl -w \"vm.max_map_count=" << expected << "\"'";
    }
  }

  // test zone_reclaim_mode
  try {
    std::string value =
        basics::FileUtils::slurp("/proc/sys/vm/zone_reclaim_mode");
    uint64_t v = basics::StringUtils::uint64(value);
    if (v != 0) {
      // from https://www.kernel.org/doc/Documentation/sysctl/vm.txt:
      //
      //    This is value ORed together of
      //    1 = Zone reclaim on
      //    2 = Zone reclaim writes dirty pages out
      //    4 = Zone reclaim swaps pages
      //
      // https://www.poempelfox.de/blog/2010/03/19/
      LOG_TOPIC(WARN, Logger::PERFORMANCE)
          << "/proc/sys/vm/zone_reclaim_mode is set to '" << v
          << "'. It is recommended to set it to a value of 0";
      LOG_TOPIC(WARN, Logger::PERFORMANCE)
          << "execute 'sudo bash -c \"echo 0 > "
             "/proc/sys/vm/zone_reclaim_mode\"'";
    }
  } catch (...) {
    // file not found or value not convertible into integer
  }

  bool showHuge = false;
  std::vector<std::string> paths = {
      "/sys/kernel/mm/transparent_hugepage/enabled",
      "/sys/kernel/mm/transparent_hugepage/defrag"};

  for (auto file : paths) {
    try {
      std::string value = basics::FileUtils::slurp(file);
      size_t start = value.find('[');
      size_t end = value.find(']');

      if (start != std::string::npos && end != std::string::npos &&
          start < end && end - start >= 4) {
        value = value.substr(start + 1, end - start - 1);
        if (value == "always") {
          LOG_TOPIC(WARN, Logger::MEMORY)
              << file << " is set to '" << value
              << "'. It is recommended to set it to a value of 'never' "
                 "or 'madvise'";
          showHuge = true;
        }
      }
    } catch (...) {
      // file not found
    }
  }

  if (showHuge) {
    for (auto file : paths) {
      LOG_TOPIC(WARN, Logger::MEMORY)
          << "execute 'sudo bash -c \"echo madvise > " << file << "\"'";
    }
  }

  bool numa = FileUtils::exists("/sys/devices/system/node/node1");

  if (numa) {
    try {
      std::string value = basics::FileUtils::slurp("/proc/self/numa_maps");
      auto values = basics::StringUtils::split(value, '\n', '\0');

      if (!values.empty()) {
        auto first = values[0];
        auto where = first.find(' ');

        if (where != std::string::npos &&
            !StringUtils::isPrefix(first.substr(where), " interleave")) {
          LOG_TOPIC(WARN, Logger::MEMORY)
              << "It is recommended to set NUMA to interleaved.";
          LOG_TOPIC(WARN, Logger::MEMORY)
              << "put 'numactl --interleave=all' in front of your command";
        }
      }
    } catch (...) {
      // file not found
    }
  }

#endif
}

void EnvironmentFeature::start() {
#ifdef __linux__
  try {
    std::string value =
        basics::FileUtils::slurp("/proc/sys/vm/overcommit_memory");
    uint64_t v = basics::StringUtils::uint64(value);
    // from https://www.kernel.org/doc/Documentation/sysctl/vm.txt:
    //
    //   When this flag is 0, the kernel attempts to estimate the amount
    //   of free memory left when userspace requests more memory.
    //   When this flag is 1, the kernel pretends there is always enough
    //   memory until it actually runs out.
    //   When this flag is 2, the kernel uses a "never overcommit"
    //   policy that attempts to prevent any overcommit of memory.
    std::string ratio =
        basics::FileUtils::slurp("/proc/sys/vm/overcommit_ratio");
    uint64_t r = basics::StringUtils::uint64(ratio);
    // from https://www.kernel.org/doc/Documentation/sysctl/vm.txt:
    //
    //  When overcommit_memory is set to 2, the committed address
    //  space is not permitted to exceed swap plus this percentage
    //  of physical RAM.

    if (EngineSelectorFeature::engineName() == RocksDBEngine::EngineName) {
      if (v != 2) {
        LOG_TOPIC(WARN, Logger::MEMORY)
          << "/proc/sys/vm/overcommit_memory is set to '" << v
          << "'. It is recommended to set it to a value of 2";
        LOG_TOPIC(WARN, Logger::MEMORY) << "execute 'sudo bash -c \"echo 2 > "
                                        << "/proc/sys/vm/overcommit_memory\"'";
      }
    } else {
      if (v == 1) {
        LOG_TOPIC(WARN, Logger::MEMORY)
          << "/proc/sys/vm/overcommit_memory is set to '" << v
          << "'. It is recommended to set it to a value of 0 or 2";
        LOG_TOPIC(WARN, Logger::MEMORY) << "execute 'sudo bash -c \"echo 2 > "
                                        << "/proc/sys/vm/overcommit_memory\"'";
      }
    }
    if (v == 2) {
      struct sysinfo info;
      int res = sysinfo(&info);
      if (res == 0) {
        double swapSpace = static_cast<double>(info.totalswap);
        double ram = static_cast<double>(TRI_PhysicalMemory);
        double rr = (ram >= swapSpace)
            ? 100.0 * ((ram - swapSpace) / ram)
            : 0.0;
        if (static_cast<double>(r) < 0.99 * rr) {
          LOG_TOPIC(WARN, Logger::MEMORY)
            << "/proc/sys/vm/overcommit_ratio is set to '" << r
            << "'. It is recommended to set it to at least '" << std::llround(rr)
            << "' (100 * (max(0, (RAM - Swap Space)) / RAM)) to utilize all "
            << "available RAM. Setting it to this value will minimize swap "
            << "usage, but may result in more out-of-memory errors, while "
            << "setting it to 100 will allow the system to use both all "
            << "available RAM and swap space.";
          LOG_TOPIC(WARN, Logger::MEMORY) << "execute 'sudo bash -c \"echo "
                                          << std::llround(rr) << " > "
                                          << "/proc/sys/vm/overcommit_ratio\"'";
        }
      }
    }
  } catch (...) {
    // file not found or value not convertible into integer
  }
#endif
}
<|endoftext|>


<commit_before>#include "nbodysimulation.h"

typedef NBodySimulation::Record Record;

NBodySimulation::NBodySimulation(unsigned int boundary)
  : index_(1), boundary_(boundary), time_(0)
{}

//appends the internal list of spheres with the given attributes of a sphere
void NBodySimulation::addBody(Color::Color color, const Vector3& center,
  int radius, const Vector3& velocity)
{
  SimulatedBody body = SimulatedBody(center, radius, velocity);
  ManagedBody indexed_body = { index_, body, color };

  if(color == Color::Color::kBlack)
    black_bodies_.push_back(indexed_body);
  else
     bodies_.push_back(indexed_body);
  index_++;
}

//assigns the properties to the black hole and adds it to the list of black holes
void NBodySimulation::addBlackHole(const Vector3& center, int mass)
{
  SimulatedBody black_hole;
  black_hole.setCenter(center);
  black_hole.setMass(mass);
  black_holes_.push_back(black_hole);
}

void NBodySimulation::advance(double time) {
  time_ += time;
  for(ManagedBodyIterator i = bodies_.begin(); i != bodies_.end(); ++i) {
    i->body.advance(time);
  }
  for(MasslessBodyIterator i = massless_bodies_.begin(); i != massless_bodies_.end(); ++i) {
    i->advance(time);
  }
  //calculateForceFromSpheres()
  //calculateForceFromBlackHoles()
  //calculate force on each sphere
  //modify velocity on each sphere
  //
}

//n^2 iteration calculating and applying the forc
void NBodySimulation::calculateForcesFromSpheres()
{
  if(bodies_.size() <= 0) //no spheres to check collisions with
  return;

  resetForces(); //start from 0

  ManagedBodyIterator i = bodies_.begin();
  do {
    ManagedBodyIterator j = i; //not necessary to start at beginning

    //Spheres do not interact with themselves
    for(j++; j != bodies_.end(); ++j) {
      updateForce(i->body, j->body);
    }
    i++;
  } while(i != bodies_.end());
}

void NBodySimulation::calculateForcesFromBlackHoles()
{
  for(ManagedBodyIterator i = bodies_.begin(); i != bodies_.end(); ++i) {
    for(SimulatedBodyIterator j = black_holes_.begin(); j != black_holes_.end(); ++j)
      updateForce(i->body, *j);
  }
}

void NBodySimulation::updateForce(SimulatedBody &b1, SimulatedBody &b2)
{
  Gravity::PointMass m1 = { b1.getMass(), b1.getCenter() };
  Gravity::PointMass m2 = { b2.getMass(), b2.getCenter() };

  Vector3 force = Gravity::force(m1, m2, GRAVITY);
  b1.setForce(b1.getForce() + force);
  b2.setForce(b2.getForce() + force * -1);
}

void NBodySimulation::resetForces()
{
  typedef std::list<NBodySimulation::ManagedBody>::iterator ManagedBodyIterator;
  for(ManagedBodyIterator i = bodies_.begin(); i != bodies_.end(); ++i)
    i->body.setForce(Vector3(0,0,0));
}

/*
//Returns a vector of records detailing how and when the spheres collided
std::vector<NBodySimulation::Record> NBodySimulation::calculateEliminations()
{
  records_.clear();
  calculateAllCollisions();
  recordEliminations();
  return records_;
}

//ManagedBodyIteratorates through list of all collisions and records only the ones that result
//in eliminations.
void NBodySimulation::recordEliminations()
{
  assert(collisions_.size() > 0);
  collisions_.sort(); //collisions are dependent on time occured
  std::list<Collision>::iterator i;

  do {
    i = collisions_.begin();

    //Only the smaller sphere is destroyed
    const IndexedSphere* destroyedSphere = addEliminationRecord(*i);

    //The rest of the collisions occur in the future. Because the smaller
    //sphere was destroyed, it will no longer have a chance to collide with
    //other spheres.
    while(i != collisions_.end()) {
      if(i->left == destroyedSphere || i->right == destroyedSphere) {
        i = collisions_.erase(i);
      }
      else
        i++;
    };

    //loop until all collisions have been handled
  } while(collisions_.size() > 0);
}

//adds the record to records_ and returns the sphere that was eliminated
const NBodySimulation::IndexedSphere*
  NBodySimulation::addEliminationRecord(const Collision &c)
{
    const IndexedSphere* destroyedSphere;
    bool isBoundaryCollision;

    if(c.right == NULL) {//boundary collision
      destroyedSphere = c.left;
      isBoundaryCollision = false;
    } else { //eliminate the smaller sphere
      destroyedSphere = smallerSphere(c.left, c.right);
      isBoundaryCollision = true;
    }

    //record the collision
    records_.push_back(Record(
      destroyedSphere->index,
      static_cast<int>(c.time),
      isBoundaryCollision
    ));

    return destroyedSphere;
}

//It will return the smallest, positive time of collision. If there is only
//  one possible time of collision, it will return that.
//pre: size of times > 0
double NBodySimulation::smallestTime(const std::vector<double>& times)
{
  assert(times.size() > 0);

  std::vector<double>::const_iterator i;
  double smallestTime = std::numeric_limits<double>::max();

  for(i = times.begin(); i != times.end(); ++i) {
    if(*i >= 0 && *i < smallestTime)
      smallestTime = *i;
  }

  return smallestTime;
}

//n^2 traversal creating complete list of all possible collisions
void NBodySimulation::calculateAllCollisions()
{
  if(bodies_.size() <= 0) //no spheres to check collisions with
    return;
  typedef std::list<NBodySimulation::IndexedSphere*>::iterator ManagedBodyIterator;

  ManagedBodyIterator i = bodies_.begin();
  do {
    //add the collision with the boundary
    calculateCollision(*i, NULL);

    ManagedBodyIterator j = i; //not necessary to start at beginning

    //Spheres cannot collide with themselves
    for(j++; j != bodies_.end(); ++j) {
      calculateCollision(*i, *j); //add collision between the two spheres
    }
    i++;
  } while(i != bodies_.end());
}

//Calculates collision times and adds soonest value to collisions_
void NBodySimulation::calculateCollision(const IndexedSphere* left, const IndexedSphere* right)
{
  std::vector<double> times;
  if(right == NULL) {  //colliding with boundary
    times = boundaryCollisionTimes(left->sphere);
  } else {
    times = COLLISION::calculateCollisionTimes(left->sphere, right->sphere);
  }

  if(times.size() > 0) {
    collisions_.push_back(
      Collision(smallestTime(times), left, right)
    );
  }
}

//will not add boundary collisions at t=0
std::vector<double> NBodySimulation::boundaryCollisionTimes(const MovingSphere &sphere)
{
  std::vector<double> times;
  int radius = sphere.getRadius();
  Vector3 position = sphere.getCenter();
  Vector3 velocity = sphere.getVelocity();

  for(int i = 0; i < 3; ++i) {
    if(velocity[i] != 0) { //stationay spheres will not collide with the boundary
      //calculates time it takes for a sphere to collide with the plane
      //x,y,z = 0, and x,y,z = boundary_
       times.push_back(static_cast<double>((boundary_ - position[i] - radius))/velocity[i]);
       times.push_back(static_cast<double>((0 - position[i] + radius))/velocity[i]);
    }
  }

  return times;
}

//returns the sphere with the smaller radius
const NBodySimulation::IndexedSphere*
  NBodySimulation::smallerSphere(const IndexedSphere* lhs, const IndexedSphere* rhs)
{
  assert(("Spheres cannot be null.", lhs != NULL && rhs != NULL));
  return lhs->sphere.getRadius() <= rhs->sphere.getRadius() ? lhs : rhs;
}
*/<commit_msg>Implemented sphere-sphere collision detection<commit_after>#include "nbodysimulation.h"

typedef NBodySimulation::Record Record;

NBodySimulation::NBodySimulation(unsigned int boundary)
  : index_(1), boundary_(boundary), time_(0)
{}

//appends the internal list of spheres with the given attributes of a sphere
void NBodySimulation::addBody(Color::Color color, const Vector3& center,
  int radius, const Vector3& velocity)
{
  // initializes with acceleration of 0 and mass equal to radius
  SimulatedBody body =
    SimulatedBody(center, radius, velocity, Vector3(0,0,0), radius);

  ManagedBody indexed_body = { index_, body, color };

  if(color == Color::Color::kBlack)
    massless_bodies_.push_back(indexed_body);
  else
     bodies_.push_back(indexed_body);

  index_++;
}

//assigns the properties to the black hole and adds it to the list of black holes
void NBodySimulation::addBlackHole(const Vector3& center, int mass)
{
  SimulatedBody black_hole;
  black_hole.setCenter(center);
  black_hole.setMass(mass);
  black_holes_.push_back(black_hole);
}

// calculates the forces for the current frame and advances the spheres by the
// given time interval
void NBodySimulation::advance(double time) {

  calculateForcesFromSpheres();
  calculateForcesFromBlackHoles();

  for(ManagedBodyIterator i = bodies_.begin(); i != bodies_.end(); ++i) {
    i->body.advance(time);
  }
  for(ManagedBodyIterator i = massless_bodies_.begin(); i != massless_bodies_.end(); ++i) {
    i->body.advance(time);
  }

  time_ += time;
}

void NBodySimulation::calculateForcesFromBlackHoles()
{
  for(ManagedBodyIterator i = bodies_.begin(); i != bodies_.end(); ++i) {
    for(SimulatedBodyIterator j = black_holes_.begin(); j != black_holes_.end(); ++j) {
      updateForce(i->body, *j); // calculates force between each sphere and black hole
    }
  }
}

//n^2 iteration calculating and applying the forc
void NBodySimulation::calculateForcesFromSpheres()
{
  if(bodies_.size() <= 0) //no spheres to check collisions with
  return;

  resetForces(); //start from 0

  ManagedBodyIterator i = bodies_.begin();
  do {
    ManagedBodyIterator j = i; //not necessary to start at beginning

    //Spheres do not interact with themselves
    for(j++; j != bodies_.end(); ++j) {
      updateForce(i->body, j->body);
    }
    i++;
  } while(i != bodies_.end());
}

void NBodySimulation::calculateForcesFromBlackHoles()
{
  for(ManagedBodyIterator i = bodies_.begin(); i != bodies_.end(); ++i) {
    for(SimulatedBodyIterator j = black_holes_.begin(); j != black_holes_.end(); ++j)
      updateForce(i->body, *j);
  }
}

void NBodySimulation::updateForce(SimulatedBody &b1, SimulatedBody &b2)
{
  Gravity::PointMass m1 = { b1.getMass(), b1.getCenter() };
  Gravity::PointMass m2 = { b2.getMass(), b2.getCenter() };

  Vector3 force = Gravity::force(m1, m2, GRAVITY);
  b1.setForce(b1.getForce() + force);
  b2.setForce(b2.getForce() + force * -1);
}

void NBodySimulation::resetForces()
{
  typedef std::list<NBodySimulation::ManagedBody>::iterator ManagedBodyIterator;
  for(ManagedBodyIterator i = bodies_.begin(); i != bodies_.end(); ++i)
    i->body.setForce(Vector3(0,0,0));
}

//Returns a vector of records detailing how and when the bodies collided
std::vector<NBodySimulation::Record> NBodySimulation::getSimulationResults()
{
  return records_;
}

// run until all spheres have collided
void NBodySimulation::runSimulation()
{
  // check collisions
  while(! bodies_.empty() && ! massless_bodies_.empty()) { //or stable orbits
    advance(TIMEINTERVAL);
    // find overlaps
    // remove overlaps
  }
}

//n^2 traversal creating complete list of all possible collisions
void NBodySimulation::findAllOverlaps()
{
  if(bodies_.size() <= 0) //no spheres to check collisions with
    return;

  std::list<Collision> collisions;

  ManagedBodyIterator i = bodies_.begin();
  do {
    ManagedBodyIterator j = i; //not necessary to start at beginning

    //Spheres cannot collide with themselves
    for(j++; j != bodies_.end(); ++j) {
      if(COLLISION::isOverlapping(i->body, j->body)) {
        //record collision
        determineResult(i->body, j->body);
        //remove object
      }
    }
    //*TODO* check boundary collision
    i++;
  } while(i != bodies_.end());
}

//Returns the sphere that is destroyed
const NBodySimulation::ManagedBody* NBodySimulation::determineResult(const ManagedBody &left, const ManagedBody &right)
{
  if(left.color == Color::kBlack && right.color == Color::kBlack)
    return NULL; // no sphere is destroyed
  if(left.color == Color::kBlack)
    return &right;
  if(right.color == Color::kBlack)
    return &left;

  // return the sphere with a smaller radius
  return left.body.getRadius() <= right.body.getRadius() ? &left : &right;
}

/*

//ManagedBodyIteratorates through list of all collisions and records only the ones that result
//in eliminations.
void NBodySimulation::recordEliminations()
{
  assert(collisions_.size() > 0);
  collisions_.sort(); //collisions are dependent on time occured
  std::list<Collision>::iterator i;

  do {
    i = collisions_.begin();

    //Only the smaller sphere is destroyed
    const IndexedSphere* destroyedSphere = addEliminationRecord(*i);

    //The rest of the collisions occur in the future. Because the smaller
    //sphere was destroyed, it will no longer have a chance to collide with
    //other spheres.
    while(i != collisions_.end()) {
      if(i->left == destroyedSphere || i->right == destroyedSphere) {
        i = collisions_.erase(i);
      }
      else
        i++;
    };

    //loop until all collisions have been handled
  } while(collisions_.size() > 0);
}

//adds the record to records_ and returns the sphere that was eliminated
const NBodySimulation::IndexedSphere*
  NBodySimulation::addEliminationRecord(const Collision &c)
{
    const IndexedSphere* destroyedSphere;
    bool isBoundaryCollision;

    if(c.right == NULL) {//boundary collision
      destroyedSphere = c.left;
      isBoundaryCollision = false;
    } else { //eliminate the smaller sphere
      destroyedSphere = smallerSphere(c.left, c.right);
      isBoundaryCollision = true;
    }

    //record the collision
    records_.push_back(Record(
      destroyedSphere->index,
      static_cast<int>(c.time),
      isBoundaryCollision
    ));

    return destroyedSphere;
}

//It will return the smallest, positive time of collision. If there is only
//  one possible time of collision, it will return that.
//pre: size of times > 0
double NBodySimulation::smallestTime(const std::vector<double>& times)
{
  assert(times.size() > 0);

  std::vector<double>::const_iterator i;
  double smallestTime = std::numeric_limits<double>::max();

  for(i = times.begin(); i != times.end(); ++i) {
    if(*i >= 0 && *i < smallestTime)
      smallestTime = *i;
  }

  return smallestTime;
}

//Calculates collision times and adds soonest value to collisions_
void NBodySimulation::calculateCollision(const IndexedSphere* left, const IndexedSphere* right)
{
  std::vector<double> times;
  if(right == NULL) {  //colliding with boundary
    times = boundaryCollisionTimes(left->sphere);
  } else {
    times = COLLISION::calculateCollisionTimes(left->sphere, right->sphere);
  }

  if(times.size() > 0) {
    collisions_.push_back(
      Collision(smallestTime(times), left, right)
    );
  }
}

//will not add boundary collisions at t=0
std::vector<double> NBodySimulation::boundaryCollisionTimes(const MovingSphere &sphere)
{
  std::vector<double> times;
  int radius = sphere.getRadius();
  Vector3 position = sphere.getCenter();
  Vector3 velocity = sphere.getVelocity();

  for(int i = 0; i < 3; ++i) {
    if(velocity[i] != 0) { //stationay spheres will not collide with the boundary
      //calculates time it takes for a sphere to collide with the plane
      //x,y,z = 0, and x,y,z = boundary_
       times.push_back(static_cast<double>((boundary_ - position[i] - radius))/velocity[i]);
       times.push_back(static_cast<double>((0 - position[i] + radius))/velocity[i]);
    }
  }

  return times;
}

//returns the sphere with the smaller radius
const NBodySimulation::IndexedSphere*
  NBodySimulation::smallerSphere(const IndexedSphere* lhs, const IndexedSphere* rhs)
{
  assert(("Spheres cannot be null.", lhs != NULL && rhs != NULL));
  return lhs->sphere.getRadius() <= rhs->sphere.getRadius() ? lhs : rhs;
}
*/<|endoftext|>


<commit_before>// For conditions of distribution and use, see copyright notice in license.txt

#include "StableHeaders.h"
#include "QuaternionDecorator.h"

namespace PythonScript {

    Quaternion* QuaternionDecorator::new_Quaternion(const float x, const float y, const float z, const float w) { return new Quaternion(x, y, z, w); }
    Quaternion* QuaternionDecorator::new_Quaternion(const float x, const float y, const float z) { return new Quaternion(x, y, z); }
    Quaternion* QuaternionDecorator::new_Quaternion(const Vector3df& vec) { return new Quaternion(vec); }
    Quaternion* QuaternionDecorator::new_Quaternion(const float angle, const Vector3df& vec) { return new Quaternion(angle, vec); }
    void QuaternionDecorator::delete_Quaternion(Quaternion* self) { delete self; }

    float QuaternionDecorator::x(Quaternion* self) { return self->x; }
    float QuaternionDecorator::y(Quaternion* self) { return self->y; }
    float QuaternionDecorator::z(Quaternion* self) { return self->z; }
    float QuaternionDecorator::w(Quaternion* self) { return self->w; }

    bool QuaternionDecorator::equals(Quaternion* self, const Quaternion& other, const float tolerance) { return self->equals(other, tolerance); }

    void QuaternionDecorator::setx(Quaternion* self, float value) { self->x = value; }
    void QuaternionDecorator::sety(Quaternion* self, float value) { self->y = value; }
    void QuaternionDecorator::setz(Quaternion* self, float value) { self->z = value; }
    void QuaternionDecorator::setw(Quaternion* self, float value) { self->w = value; }

    float QuaternionDecorator::dotProduct(Quaternion* self, const Quaternion& other)
    {
        return self->dotProduct(other);
    }

    void QuaternionDecorator::toEuler(Quaternion* self, Vector3df& euler) {
        self->toEuler(euler);
    }

    void QuaternionDecorator::set(Quaternion* self, float x, float y, float z, float w) {
        self->set(x, y, z, w);
    }

    void QuaternionDecorator::set(Quaternion* self, float x, float y, float z, float w) {
        self->set(x, y, z);
    }

    void QuaternionDecorator::set(Quaternion* self, const Vector3df& euler) {
        self->set(euler);
    }

    void QuaternionDecorator::normalize(Quaternion* self)
    {
        self->normalize();
    }

    void QuaternionDecorator::makeInverse(Quaternion* self)
    {
        self->makeInverse();
    }

    void QuaternionDecorator::slerp(Quaternion* self, Quaternion q1, Quaternion q2, float interpolate)
    {
        self->slerp(q1, q2, interpolate);
    }

    void QuaternionDecorator::fromAngleAxis(Quaternion* self, float angle, const Vector3df& axis)
    {
        self->fromAngleAxis(angle, axis);
    }

    void QuaternionDecorator::toAngleAxis(Quaternion* self, float& angle, Vector3df& axis)
    {
        self->toAngleAxis(angle, axis);
    }

    void QuaternionDecorator::makeIdentity(Quaternion* self)
    {
        self->makeIdentity();
    }

    void QuaternionDecorator::rotationFromTo(Quaternion* self, const Vector3df& from, const Vector3df& to)
    {
        self->rotationFromTo(from, to);
    }
}

<commit_msg>Small reorg<commit_after>// For conditions of distribution and use, see copyright notice in license.txt

#include "StableHeaders.h"
#include "QuaternionDecorator.h"

namespace PythonScript {

    Quaternion* QuaternionDecorator::new_Quaternion(const float x, const float y, const float z, const float w)
    {
        return new Quaternion(x, y, z, w);
    }

    Quaternion* QuaternionDecorator::new_Quaternion(const float x, const float y, const float z)
    {
        return new Quaternion(x, y, z);
    }

    Quaternion* QuaternionDecorator::new_Quaternion(const Vector3df& vec)
    {
        return new Quaternion(vec);
    }

    Quaternion* QuaternionDecorator::new_Quaternion(const float angle, const Vector3df& vec)
    {
        return new Quaternion(angle, vec);
    }

    void QuaternionDecorator::delete_Quaternion(Quaternion* self)
    {
        delete self;
    }

    float QuaternionDecorator::x(Quaternion* self)
    {
        return self->x;
    }

    float QuaternionDecorator::y(Quaternion* self)
    {
        return self->y;
    }

    float QuaternionDecorator::z(Quaternion* self)
    {
        return self->z;
    }

    float QuaternionDecorator::w(Quaternion* self)
    {
        return self->w;
    }

    bool QuaternionDecorator::equals(Quaternion* self, const Quaternion& other, const float tolerance)
    {
        return self->equals(other, tolerance);
    }

    void QuaternionDecorator::setx(Quaternion* self, float value)
    {
        self->x = value;
    }

    void QuaternionDecorator::sety(Quaternion* self, float value)
    {
        self->y = value;
    }

    void QuaternionDecorator::setz(Quaternion* self, float value)
    {
        self->z = value;
    }

    void QuaternionDecorator::setw(Quaternion* self, float value)
    {
        self->w = value;
    }

    float QuaternionDecorator::dotProduct(Quaternion* self, const Quaternion& other)
    {
        return self->dotProduct(other);
    }

    void QuaternionDecorator::toEuler(Quaternion* self, Vector3df& euler)
    {
        self->toEuler(euler);
    }

    void QuaternionDecorator::set(Quaternion* self, float x, float y, float z, float w)
    {
        self->set(x, y, z, w);
    }

    void QuaternionDecorator::set(Quaternion* self, float x, float y, float z, float w)
    {
        self->set(x, y, z);
    }

    void QuaternionDecorator::set(Quaternion* self, const Vector3df& euler)
    {
        self->set(euler);
    }

    void QuaternionDecorator::normalize(Quaternion* self)
    {
        self->normalize();
    }

    void QuaternionDecorator::makeInverse(Quaternion* self)
    {
        self->makeInverse();
    }

    void QuaternionDecorator::slerp(Quaternion* self, Quaternion q1, Quaternion q2, float interpolate)
    {
        self->slerp(q1, q2, interpolate);
    }

    void QuaternionDecorator::fromAngleAxis(Quaternion* self, float angle, const Vector3df& axis)
    {
        self->fromAngleAxis(angle, axis);
    }

    void QuaternionDecorator::toAngleAxis(Quaternion* self, float& angle, Vector3df& axis)
    {
        self->toAngleAxis(angle, axis);
    }

    void QuaternionDecorator::makeIdentity(Quaternion* self)
    {
        self->makeIdentity();
    }

    void QuaternionDecorator::rotationFromTo(Quaternion* self, const Vector3df& from, const Vector3df& to)
    {
        self->rotationFromTo(from, to);
    }
}

<|endoftext|>


<commit_before>//===- AArch64MachineLegalizer.cpp -------------------------------*- C++ -*-==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
/// \file
/// This file implements the targeting of the Machinelegalizer class for
/// AArch64.
/// \todo This should be generated by TableGen.
//===----------------------------------------------------------------------===//

#include "AArch64MachineLegalizer.h"
#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/Target/TargetOpcodes.h"

using namespace llvm;

#ifndef LLVM_BUILD_GLOBAL_ISEL
#error "You shouldn't build this"
#endif

AArch64MachineLegalizer::AArch64MachineLegalizer() {
  setAction(TargetOpcode::G_ADD, LLT::vector(2, 64), Legal);
  computeTables();
}
<commit_msg>[AArch64][GlobalISel] Mark basic binops/memops as legal.<commit_after>//===- AArch64MachineLegalizer.cpp -------------------------------*- C++ -*-==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
/// \file
/// This file implements the targeting of the Machinelegalizer class for
/// AArch64.
/// \todo This should be generated by TableGen.
//===----------------------------------------------------------------------===//

#include "AArch64MachineLegalizer.h"
#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/Target/TargetOpcodes.h"

using namespace llvm;

#ifndef LLVM_BUILD_GLOBAL_ISEL
#error "You shouldn't build this"
#endif

AArch64MachineLegalizer::AArch64MachineLegalizer() {
  using namespace TargetOpcode;
  const LLT s32 = LLT::scalar(32);
  const LLT s64 = LLT::scalar(64);
  const LLT v2s32 = LLT::vector(2, 32);
  const LLT v4s32 = LLT::vector(4, 32);
  const LLT v2s64 = LLT::vector(2, 64);

  for (auto BinOp : {G_ADD, G_SUB, G_AND, G_OR, G_XOR})
    for (auto Ty : {s32, s64, v2s32, v4s32, v2s64})
      setAction(BinOp, Ty, Legal);

  for (auto MemOp : {G_LOAD, G_STORE})
    for (auto Ty : {s32, s64})
      setAction(MemOp, Ty, Legal);

  setAction(G_BR, LLT::unsized(), Legal);

  computeTables();
}
<|endoftext|>