text:
<?php

/**
 * folder controller for Felamimail
 *
 * @package     Felamimail
 * @subpackage  Controller
 */
class Felamimail_Controller_Folder extends Tinebase_Controller_Abstract implements Tinebase_Controller_SearchInterface
{
    /**
     * application name (is needed in checkRight())
     *
     * @var string
     */
    protected $_applicationName = 'Felamimail';

    /**
     * last search count (2 dim array: userId => accountId => count)
     *
     * @var array
     */
    protected $_lastSearchCount = array();

    /**
     * default system folder names
     *
     * @var array
     */
    protected $_systemFolders = array('inbox', 'drafts', 'sent', 'templates', 'junk', 'trash');

    /**
     * folder delimiter/separator
     *
     * @var string
     */
    protected $_delimiter = '/';

    /**
     * folder backend
     *
     * @var Felamimail_Backend_Folder
     */
    protected $_backend = NULL;

    /**
     * cache controller
     *
     * @var Felamimail_Controller_Cache_Folder
     */
    protected $_cacheController = NULL;

    /**
     * holds the instance of the singleton
     *
     * @var Felamimail_Controller_Folder
     */
    private static $_instance = NULL;

    /**
     * the constructor
     *
     * don't use the constructor. use the singleton
     */
    private function __construct() {
        $this->_backend = new Felamimail_Backend_Folder();
        $this->_cacheController = Felamimail_Controller_Cache_Folder::getInstance();
    }

    /**
     * don't clone. Use the singleton.
     *
     */
    private function __clone()
    {
    }

    /**
     * the singleton pattern
     *
     * @return Felamimail_Controller_Folder
     */
    public static function getInstance()
    {
        if (self::$_instance === NULL) {
            self::$_instance = new Felamimail_Controller_Folder();
        }

        return self::$_instance;
    }

    /************************************* public functions *************************************/

    /**
     * get list of records
     *
     * @param Tinebase_Model_Filter_FilterGroup|optional $_filter
     * @param Tinebase_Model_Pagination|optional $_pagination
     * @param bool $_getRelations
     * @return Tinebase_Record_RecordSet
     */
    public function search(Tinebase_Model_Filter_FilterGroup $_filter = NULL, Tinebase_Record_Interface $_pagination = NULL, $_getRelations = FALSE, $_onlyIds = FALSE)
    {
        $filterValues = $this->_extractFilter($_filter);

        if (empty($filterValues['account_id'])) {
            throw new Felamimail_Exception('No account id set in search filter. Check default account preference!');
        }

        // get folders from db
        $filter = new Felamimail_Model_FolderFilter(array(
            array('field' => 'parent',      'operator' => 'equals', 'value' => $filterValues['globalname']),
            array('field' => 'account_id',  'operator' => 'equals', 'value' => $filterValues['account_id'])
        ));
        $result = $this->_backend->search($filter);
        if (count($result) == 0) {
            // try to get folders from imap server
            $result = $this->_cacheController->update($filterValues['account_id'], $filterValues['globalname']);
        }

        $this->_lastSearchCount[Tinebase_Core::getUser()->getId()][$filterValues['account_id']] = count($result);

        // sort folders
        $account = Felamimail_Controller_Account::getInstance()->get($filterValues['account_id']);
        $result = $this->_sortFolders($result, $filterValues['globalname']);

        return $result;
    }

    /**
     * Gets total count of search with $_filter
     *
     * @param Tinebase_Model_Filter_FilterGroup $_filter
     * @return int
     */
    public function searchCount(Tinebase_Model_Filter_FilterGroup $_filter)
    {
        $filterValues = $this->_extractFilter($_filter);

        return $this->_lastSearchCount[Tinebase_Core::getUser()->getId()][$filterValues['account_id']];
    }

    /**
     * get single folder
     *
     * @param string $_id
     * @return Felamimail_Model_Folder
     */
    public function get($_id)
    {
        return $this->_backend->get($_id);
    }

    /**
     * get multiple folders
     *
     * @param string|array $_ids
     * @return Tinebase_RecordSet
     */
    public function getMultiple($_ids)
    {
        return $this->_backend->getMultiple($_ids);
    }

    /**
     * get saved folder record by backend and globalname
     *
     * @param  mixed   $_accountId
     * @param  string  $_globalName
     * @return Felamimail_Model_Folder
     */
    public function getByBackendAndGlobalName($_accountId, $_globalName)
    {
        $accountId = ($_accountId instanceof Felamimail_Model_Account) ? $_accountId->getId() : $_accountId;

        $filter = new Felamimail_Model_FolderFilter(array(
            array('field' => 'account_id', 'operator' => 'equals', 'value' => $accountId),
            array('field' => 'globalname', 'operator' => 'equals', 'value' => $_globalName),
        ));

        $folders = $this->_backend->search($filter);

        if (count($folders) > 0) {
            $result = $folders->getFirstRecord();
        } else {
            throw new Tinebase_Exception_NotFound("Folder $_globalName not found.");
        }

        return $result;
    }

    /**
     * create folder
     *
     * @param string|Felamimail_Model_Account $_accountId
     * @param string $_folderName to create
     * @param string $_parentFolder
     * @return Felamimail_Model_Folder
     * @throws Felamimail_Exception_IMAPServiceUnavailable
     */
    public function create($_accountId, $_folderName, $_parentFolder = '')
    {
        $account = ($_accountId instanceof Felamimail_Controller_Account) ? $_accountId : Felamimail_Controller_Account::getInstance()->get($_accountId);
        $this->_delimiter = $account->delimiter;

        $foldername = $this->_prepareFolderName($_folderName);
        $globalname = (empty($_parentFolder)) ? $foldername : $_parentFolder . $this->_delimiter . $foldername;
        if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Trying to create new folder: ' . $globalname . ' (parent: ' . $_parentFolder . ')');

        $imap = Felamimail_Backend_ImapFactory::factory($account);

        try {
            $imap->createFolder(
                Felamimail_Model_Folder::encodeFolderName($foldername),
                (empty($_parentFolder)) ? NULL : Felamimail_Model_Folder::encodeFolderName($_parentFolder),
                $this->_delimiter
            );

            // create new folder
            $folder = new Felamimail_Model_Folder(array(
                'localname'     => $foldername,
                'globalname'    => $globalname,
                'account_id'    => $account->getId(),
                'parent'        => $_parentFolder
            ));

            $folder = $this->_backend->create($folder);

            if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Create new folder: ' . $globalname);

        } catch (Zend_Mail_Storage_Exception $zmse) {
            // perhaps the folder already exists
            if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Could not create new folder: ' . $globalname . ' (' . $zmse->getMessage() . ')');

            // reload folder cache of parent
            $parentSubs = $this->_cacheController->update($account, $_parentFolder);
            $folder = $parentSubs->filter('globalname', $globalname)->getFirstRecord();
            if ($folder === NULL) {
                throw new Felamimail_Exception_IMAPServiceUnavailable($zmse->getMessage());
            }
        }

        // update parent (has_children)
        $this->_updateHasChildren($_accountId, $_parentFolder, 1);

        return $folder;
    }

    /**
     * prepare foldername given by user (remove some bad chars)
     *
     * @param string $_folderName
     * @return string
     */
    protected function _prepareFolderName($_folderName)
    {
        $result = stripslashes($_folderName);
        $result = str_replace(array('/', $this->_delimiter), '', $result);
        return $result;
    }

    /**
     * update single folder
     *
     * @param Felamimail_Model_Folder $_folder
     * @return Felamimail_Model_Folder
     */
    public function update(Felamimail_Model_Folder $_folder)
    {
        return $this->_backend->update($_folder);
    }

    /**
     * update single folders counter
     *
     * @param  mixed  $_folderId
     * @param  array  $_counters
     * @return Felamimail_Model_Folder
     */
    public function updateFolderCounter($_folderId, array $_counters)
    {
        return $this->_backend->updateFolderCounter($_folderId, $_counters);
    }

    /**
     * remove folder
     *
     * @param string $_accountId
     * @param string $_folderName globalName (complete path) of folder to delete
     * @param boolean $_recursive
     * @return void
     */
    public function delete($_accountId, $_folderName, $_recursive = FALSE)
    {
        try {
            $folder = $this->getByBackendAndGlobalName($_accountId, $_folderName);
        } catch (Tinebase_Exception_NotFound $tenf) {
            Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' Trying to delete non-existant folder ' . $_folderName);
            $folder = NULL;
        }

        // check if folder has subfolders and throw exception if that is the case / OR: delete subfolders if recursive param is TRUE
        // @todo this should not be a Tinebase_Exception_AccessDenied -> we have to create a new exception and call the fmail exception handler when deleting/adding/renaming folders
        $subfolders = $this->getSubfolders($_accountId, $_folderName);
        if (count($subfolders) > 0 && $folder) {
            if ($_recursive) {
                $this->deleteSubfolders($folder, $subfolders);
            } else {
                throw new Tinebase_Exception_AccessDenied('Could not delete folder ' . $_folderName . ' because it has subfolders.');
            }
        }

        $this->_deleteFolderOnIMAP($_accountId, $_folderName);
        $this->_deleteFolderInCache($_accountId, $folder);
    }

    /**
     * rename folder on imap server
     *
     * @param string|Felamimail_Model_Account $_account
     * @param string $_folderName
     * @throws Felamimail_Exception_IMAPFolderNotFound
     * @throws Felamimail_Exception_IMAP
     */
    protected function _deleteFolderOnIMAP($_accountId, $_folderName)
    {
        try {
            $imap = Felamimail_Backend_ImapFactory::factory($_accountId);
            $imap->removeFolder(Felamimail_Model_Folder::encodeFolderName($_folderName));
        } catch (Zend_Mail_Storage_Exception $zmse) {
            try {
                $imap->selectFolder(Felamimail_Model_Folder::encodeFolderName($_folderName));
            } catch (Zend_Mail_Storage_Exception $zmse2) {
                throw new Felamimail_Exception_IMAPFolderNotFound('Folder not found (error: ' . $zmse2->getMessage() . ').');
            }

            throw new Felamimail_Exception_IMAP('Could not delete folder ' . $_folderName . '. IMAP Error: ' . $zmse->getMessage());
        }
    }

    /**
     * delete folder in cache
     *
     * @param string|Felamimail_Model_Account $_account
     * @param Felamimail_Model_Folder $_folder
     */
    protected function _deleteFolderInCache($_accountId, $_folder)
    {
        if ($_folder === NULL) {
            return;
        }

        Felamimail_Controller_Message::getInstance()->deleteByFolder($_folder);
        $this->_backend->delete($_folder->getId());

        Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Deleted folder ' . $_folder->globalname);
        $this->_updateHasChildren($_accountId, $_folder->parent);
    }

    /**
     * rename folder
     *
     * @param string $_accountId
     * @param string $_newLocalName
     * @param string $_oldGlobalName
     * @return Felamimail_Model_Folder
     */
    public function rename($_accountId, $_newLocalName, $_oldGlobalName)
    {
        $account = Felamimail_Controller_Account::getInstance()->get($_accountId);
        $this->_delimiter = $account->delimiter;

        $newLocalName = $this->_prepareFolderName($_newLocalName);
        $newGlobalName = $this->_buildNewGlobalName($newLocalName, $_oldGlobalName);

        if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Renaming ... ' . $_oldGlobalName . ' -> ' . $newGlobalName);

        $this->_renameFolderOnIMAP($account, $newGlobalName, $_oldGlobalName);
        $folder = $this->_renameFolderInCache($account, $newGlobalName, $_oldGlobalName, $newLocalName);
        $this->_updateSubfoldersAfterRename($account, $newGlobalName, $_oldGlobalName);

        return $folder;
    }

    /**
     * remove old localname and build new globalname
     *
     * @param string $_newLocalName
     * @param string $_oldGlobalName
     * @return string
     *
     * @todo generalize this
     */
    protected function _buildNewGlobalName($_newLocalName, $_oldGlobalName)
    {
        $globalNameParts = explode($this->_delimiter, $_oldGlobalName);
        array_pop($globalNameParts);
        if (! empty($_newLocalName)) {
            array_push($globalNameParts, $_newLocalName);
        }
        $newGlobalName = implode($this->_delimiter, $globalNameParts);

        return $newGlobalName;
    }

    /**
     * rename folder on imap server
     *
     * @param Felamimail_Model_Account $_account
     * @param string $_newGlobalName
     * @param string $_oldGlobalName
     * @throws Felamimail_Exception_IMAPFolderNotFound
     */
    protected function _renameFolderOnIMAP(Felamimail_Model_Account $_account, $_newGlobalName, $_oldGlobalName)
    {
        $imap = Felamimail_Backend_ImapFactory::factory($_account);

        try {
            $imap->renameFolder(Felamimail_Model_Folder::encodeFolderName($_oldGlobalName), Felamimail_Model_Folder::encodeFolderName($_newGlobalName));
        } catch (Zend_Mail_Storage_Exception $zmse) {
            if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__
                . ' Folder could have been renamed / deleted by another client.');

            throw new Felamimail_Exception_IMAPFolderNotFound('Folder not found (error: ' . $zmse->getMessage() . ').');
        }
    }

    /**
     * rename folder in cache
     *
     * @param Felamimail_Model_Account $_account
     * @param string $_newGlobalName
     * @param string $_oldGlobalName
     * @param string $_newLocalName
     * @return Felamimail_Model_Folder
     * @throws Tinebase_Exception_NotFound
     */
    protected function _renameFolderInCache(Felamimail_Model_Account $_account, $_newGlobalName, $_oldGlobalName, $_newLocalName)
    {
        try {
            $folder = $this->getByBackendAndGlobalName($_account, $_oldGlobalName);
            $folder->globalname = $_newGlobalName;
            $folder->localname = $_newLocalName;
            $folder = $this->update($folder);

        } catch (Tinebase_Exception_NotFound $tenf) {
            Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' Trying to rename non-existant folder ' . $_oldGlobalName);
            throw $tenf;
        }

        return $folder;
    }

    /**
     * loop subfolders (recursive) and replace new localname in globalname path
     *
     * @param Felamimail_Model_Account $_account
     * @param string $_newGlobalName
     * @param string $_oldGlobalName
     */
    protected function _updateSubfoldersAfterRename(Felamimail_Model_Account $_account, $_newGlobalName, $_oldGlobalName)
    {
        $subfolders = $this->getSubfolders($_account, $_oldGlobalName);
        foreach ($subfolders as $subfolder) {
            if ($_newGlobalName != $subfolder->globalname) {
                $newSubfolderGlobalname = str_replace($_oldGlobalName, $_newGlobalName, $subfolder->globalname);
                if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__
                    . ' Renaming ... ' . $subfolder->globalname . ' -> ' . $newSubfolderGlobalname);

                $subfolder->globalname = $newSubfolderGlobalname;
                $this->update($subfolder);
            }
        }
    }

    /**
     * delete all messages in one folder -> be careful, they are completly removed and not moved to trash
     * -> delete subfolders if param set
     *
     * @param string $_folderId
     * @param boolean $_deleteSubfolders
     * @return Felamimail_Model_Folder
     * @throws Felamimail_Exception_IMAPServiceUnavailable
     */
    public function emptyFolder($_folderId, $_deleteSubfolders = FALSE)
    {
        $folder = $this->_backend->get($_folderId);
        $account = Felamimail_Controller_Account::getInstance()->get($folder->account_id);

        $imap = Felamimail_Backend_ImapFactory::factory($account);
        try {
            // try to delete messages in imap folder
            Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Delete all messages in folder ' . $folder->globalname);
            $imap->emptyFolder(Felamimail_Model_Folder::encodeFolderName($folder->globalname));

        } catch (Zend_Mail_Protocol_Exception $zmpe) {
            Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' ' . $zmpe->getMessage());
            throw new Felamimail_Exception_IMAPServiceUnavailable($zmpe->getMessage());
        } catch (Zend_Mail_Storage_Exception $zmse) {
            Tinebase_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . ' Folder could be empty (' . $zmse->getMessage() . ')');
        }

        if ($_deleteSubfolders) {
            $this->deleteSubfolders($folder);
        }

        $folder = Felamimail_Controller_Cache_Message::getInstance()->clear($_folderId);
        return $folder;
    }

    /**
     * delete subfolders recursivly
     *
     * @param Felamimail_Model_Folder $_folder
     * @param Tinebase_Record_RecordSet $_subfolders if we know the subfolders already
     */
    public function deleteSubfolders(Felamimail_Model_Folder $_folder, $_subfolders = NULL)
    {
        $account = Felamimail_Controller_Account::getInstance()->get($_folder->account_id);
        $subfolders = ($_subfolders === NULL) ? $this->getSubfolders($account, $_folder->globalname) : $_subfolders;

        Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Delete ' . count($subfolders) . ' subfolders of ' . $_folder->globalname);
        foreach ($subfolders as $subfolder) {
            $this->delete($account, $subfolder->globalname, TRUE);
        }
    }

    /**
     * get system folders
     *
     * @param string $_accountId
     * @return array
     *
     * @todo    update these from account settings
     */
    public function getSystemFolders($_accountId)
    {
        return $this->_systemFolders;
    }

    /************************************* protected functions *************************************/

    /**
     * extract values from folder filter
     *
     * @param Felamimail_Model_FolderFilter $_filter
     * @return array (assoc) with filter values
     *
     * @todo add AND/OR conditions for multiple filters of the same field?
     */
    protected function _extractFilter(Felamimail_Model_FolderFilter $_filter)
    {
        $result = array(
            'account_id' => Tinebase_Core::getPreference('Felamimail')->{Felamimail_Preference::DEFAULTACCOUNT},
            'globalname' => ''
        );

        $filters = $_filter->getFilterObjects();
        foreach($filters as $filter) {
            switch($filter->getField()) {
                case 'account_id':
                    $result['account_id'] = $filter->getValue();
                    break;
                case 'globalname':
                    $result['globalname'] = $filter->getValue();
                    break;
            }
        }

        return $result;
    }

    /**
     * sort folder record set
     * - begin with INBOX + other standard/system folders, add other folders
     *
     * @param Tinebase_Record_RecordSet $_folders
     * @param string $_parentFolder
     * @return Tinebase_Record_RecordSet
     */
    protected function _sortFolders(Tinebase_Record_RecordSet $_folders, $_parentFolder)
    {
        $sortedFolders = new Tinebase_Record_RecordSet('Felamimail_Model_Folder');

        $_folders->sort('localname', 'ASC', 'natcasesort');
        $_folders->addIndices(array('globalname'));

        Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Sorting subfolders of "' . $_parentFolder . '".');

        if (Tinebase_Core::isLogLevel(Zend_Log::TRACE)) Tinebase_Core::getLogger()->trace(__METHOD__ . '::' . __LINE__ . ' ' . print_r($_folders->globalname, TRUE));

        foreach ($this->_systemFolders as $systemFolderName) {
            $folders = $_folders->filter('globalname', '@^' . $systemFolderName . '$@i', TRUE);
            //if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' ' . $systemFolderName . ' => ' . print_r($folders->toArray(), TRUE));
            if (count($folders) > 0) {
                $sortedFolders->addRecord($folders->getFirstRecord());
            }
        }

        foreach ($_folders as $folder) {
            if (! in_array(strtolower($folder->globalname), $this->_systemFolders)) {
                $sortedFolders->addRecord($folder);
            }
        }

        //if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' ' . print_r($sortedFolders->globalname, TRUE));

        return $sortedFolders;
    }

    /**
     * update folder value has_children
     *
     * @param string $_globalname
     * @param integer $_value
     * @return null|Felamimail_Model_Folder
     */
    protected function _updateHasChildren($_accountId, $_globalname, $_value = NULL)
    {
        if (empty($_globalname)) {
            return NULL;
        }

        if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Checking has_children for folder ' . $_globalname);

        $account = Felamimail_Controller_Account::getInstance()->get($_accountId);

        if (! $account->has_children_support) {
            return NULL;
        }

        try {
            $folder = $this->getByBackendAndGlobalName($_accountId, $_globalname);
        } catch (Tinebase_Exception_NotFound $tenf) {
            if (Tinebase_Core::isLogLevel(Zend_Log::NOTICE)) Tinebase_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__ . ' ' .
                $tenf->getMessage());
            return NULL;
        }
        if ($_value === NULL) {
            // check if folder has children by searching in db
            $subfolders = $this->getSubfolders($account, $_globalname);
            $value = (count($subfolders) > 0) ? 1 : 0;
        } else {
            $value = $_value;
        }

        if ($folder->has_children != $value) {
            if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . ' Set new has_children value for folder ' . $_globalname . ': ' . $value);
            $folder->has_children = $value;
            $folder = $this->update($folder);
        }

        return $folder;
    }

    /**
     * get subfolders
     *
     * @param string|Felamimail_Model_Account $_account
     * @param string $_globalname
     * @return Tinebase_Record_RecordSet
     */
    public function getSubfolders($_account, $_globalname)
    {
        $account = ($_account instanceof Felamimail_Model_Account) ? $_account : Felamimail_Controller_Account::getInstance()->get($_account);
        $globalname = (empty($_globalname)) ? '' : $_globalname . $account->delimiter;

        $filter = new Felamimail_Model_FolderFilter(array(
            array('field' => 'globalname', 'operator' => 'startswith',  'value' => $globalname),
            array('field' => 'account_id', 'operator' => 'equals',      'value' => $account->getId()),
        ));

        return $this->_backend->search($filter);
    }
}


text:
<?php

namespace DMS\Bundles\BaseBundle;

use Symfony\Component\HttpKernel\Bundle\Bundle;

class DMSBaseBundle extends Bundle
{
}

redpajama_set_name: RedPajamaGithub


text:
using namespace rapidjson;

namespace chrono {
namespace vehicle {

// =============================================================================
// Definition of a chassis for a suspension test rig
class TestRigChassis : public ChRigidChassis {
  public:
    TestRigChassis();
    virtual double GetMass() const override { return m_mass; }
    virtual const ChMatrix33<>& GetInertia() const override { return m_inertia; }
    virtual const ChVector<>& GetLocalPosCOM() const override { return m_COM_loc; }
    virtual ChCoordsys<> GetLocalDriverCoordsys() const override { return m_driverCsys; }

  private:
    ChMatrix33<> m_inertia;

    static const double m_mass;
    static const ChVector<> m_inertiaXX;
    static const ChVector<> m_COM_loc;
    static const ChCoordsys<> m_driverCsys;
};

const double TestRigChassis::m_mass = 1;
const ChVector<> TestRigChassis::m_inertiaXX(1, 1, 1);
const ChVector<> TestRigChassis::m_COM_loc(0, 0, 0);
const ChCoordsys<> TestRigChassis::m_driverCsys(ChVector<>(0, 0, 0), ChQuaternion<>(1, 0, 0, 0));

TestRigChassis::TestRigChassis() : ChRigidChassis("Ground") {
    m_inertia = ChMatrix33<>(m_inertiaXX);
}

// =============================================================================
// Definition of a terrain object for use by a suspension test rig.
// Note that this assumes an ISO world frame.
class TestRigTerrain : public ChTerrain {
  public:
    TestRigTerrain();
    virtual double GetHeight(const ChVector<>& loc) const override;
    virtual ChVector<> GetNormal(const ChVector<>& loc) const override;
    virtual float GetCoefficientFriction(const ChVector<>& loc) const override;
    double m_height_L;
    double m_height_R;
};

TestRigTerrain::TestRigTerrain() : m_height_L(-1000), m_height_R(-1000) {}

double TestRigTerrain::GetHeight(const ChVector<>& loc) const {
    return (loc.y() < 0) ? m_height_R : m_height_L;
}

ChVector<> TestRigTerrain::GetNormal(const ChVector<>& loc) const {
    return ChVector<>(0, 0, 1);
}

float TestRigTerrain::GetCoefficientFriction(const ChVector<>& loc) const {
    return 0.8f;
}

// =============================================================================
// Static variables
const double ChSuspensionTestRigPlatform::m_post_hheight = 0.05;
const double ChSuspensionTestRigPlatform::m_post_radius = 0.4;

const double ChSuspensionTestRigPushrod::m_rod_length = 3;
const double ChSuspensionTestRigPushrod::m_rod_radius = 0.02;

// =============================================================================
// Base class implementation
// =============================================================================
ChSuspensionTestRig::ChSuspensionTestRig(ChWheeledVehicle& vehicle,
                                         int axle_index,
                                         int steering_index,
                                         double displ_limit,
                                         std::shared_ptr<ChTire> tire_left,
                                         std::shared_ptr<ChTire> tire_right,
                                         ChContactMethod contact_method)
    : ChVehicle("SuspensionTestRig", contact_method),
      m_displ_limit(displ_limit),
      m_ride_height(-1),
      m_vis_suspension(VisualizationType::PRIMITIVES),
      m_vis_steering(VisualizationType::PRIMITIVES),
      m_vis_wheel(VisualizationType::NONE),
      m_vis_tire(VisualizationType::PRIMITIVES),
      m_plot_output(false),
      m_plot_output_step(0),
      m_next_plot_output_time(0),
      m_csv(nullptr) {
    assert(axle_index >= 0 && axle_index < vehicle.GetNumberAxles());

    // Load suspension subsystem
    m_suspension = vehicle.GetSuspension(axle_index);
    m_suspLoc = m_suspension->GetLocation();

    // Load wheel subsystems
    m_wheel[LEFT] = vehicle.GetAxle(axle_index)->m_wheels[0];
    m_wheel[RIGHT] = vehicle.GetAxle(axle_index)->m_wheels[1];

    // Load steering subsystem (if needed)
    if (steering_index >= 0) {
        m_steering = vehicle.GetSteering(steering_index);
        m_steeringLoc = m_steering->GetPosition().pos;
        m_steeringRot = m_steering->GetPosition().rot;
    }

    m_tire[LEFT] = tire_left;
    m_tire[RIGHT] = tire_right;
}

ChSuspensionTestRig::ChSuspensionTestRig(const std::string& filename,
                                         int axle_index,
                                         double displ_limit,
                                         std::shared_ptr<ChTire> tire_left,
                                         std::shared_ptr<ChTire> tire_right,
                                         ChContactMethod contact_method)
    : ChVehicle("SuspensionTestRig", contact_method),
      m_displ_limit(displ_limit),
      m_ride_height(-1),
      m_vis_suspension(VisualizationType::PRIMITIVES),
      m_vis_steering(VisualizationType::PRIMITIVES),
      m_vis_wheel(VisualizationType::NONE),
      m_vis_tire(VisualizationType::PRIMITIVES),
      m_plot_output(false),
      m_plot_output_step(0),
      m_next_plot_output_time(0),
      m_csv(nullptr) {
    // Open and parse the input file (vehicle JSON specification file)
    Document d; ReadFileJSON(filename, d);
    if (d.IsNull())
        return;

    // Read top-level data
    assert(d.HasMember("Type"));
    assert(d.HasMember("Template"));
    assert(d.HasMember("Name"));

    // Extract the specified axle from the vehicle's list of suspension subsystems.
    // Note that we ignore antiroll bar and brake subsystems.
    // Create the suspension and wheel subsystems.
    assert(axle_index >= 0 && axle_index < d["Axles"].Size());

    std::string file_name = d["Axles"][axle_index]["Suspension Input File"].GetString();
    m_suspension = ReadSuspensionJSON(vehicle::GetDataFile(file_name));
    m_suspLoc = ReadVectorJSON(d["Axles"][axle_index]["Suspension Location"]);

    int steering_index = -1;
    if (d["Axles"][axle_index].HasMember("Steering Index")) {
        steering_index = d["Axles"][axle_index]["Steering Index"].GetInt();
    }

    file_name = d["Axles"][axle_index]["Left Wheel Input File"].GetString();
    m_wheel[VehicleSide::LEFT] = ReadWheelJSON(vehicle::GetDataFile(file_name));
    file_name = d["Axles"][axle_index]["Right Wheel Input File"].GetString();
    m_wheel[VehicleSide::RIGHT] = ReadWheelJSON(vehicle::GetDataFile(file_name));

    // Create the steering subsystem, if needed.
    if (steering_index >= 0) {
        file_name = d["Steering Subsystems"][steering_index]["Input File"].GetString();
        m_steering = ReadSteeringJSON(vehicle::GetDataFile(file_name));
        m_steeringLoc = ReadVectorJSON(d["Steering Subsystems"][steering_index]["Location"]);
        m_steeringRot = ReadQuaternionJSON(d["Steering Subsystems"][steering_index]["Orientation"]);
    }

    // Create the anti-roll bar subsystem, if one exists.
    if (d["Axles"][axle_index].HasMember("Antirollbar Input File")) {
        file_name = d["Axles"][axle_index]["Antirollbar Input File"].GetString();
        m_antirollbar = ReadAntirollbarJSON(vehicle::GetDataFile(file_name));
        m_antirollbarLoc = ReadVectorJSON(d["Axles"][axle_index]["Antirollbar Location"]);
    }

    GetLog() << "Loaded JSON: " << filename.c_str() << "\n";

    m_tire[LEFT] = tire_left;
    m_tire[RIGHT] = tire_right;
}

ChSuspensionTestRig::ChSuspensionTestRig(const std::string& filename,
                                         std::shared_ptr<ChTire> tire_left,
                                         std::shared_ptr<ChTire> tire_right,
                                         ChContactMethod contact_method)
    : ChVehicle("SuspensionTestRig", contact_method),
      m_vis_suspension(VisualizationType::PRIMITIVES),
      m_vis_steering(VisualizationType::PRIMITIVES),
      m_vis_wheel(VisualizationType::NONE),
      m_vis_tire(VisualizationType::PRIMITIVES),
      m_plot_output(false),
      m_plot_output_step(0),
      m_next_plot_output_time(0),
      m_csv(nullptr) {
    // Open and parse the input file (rig JSON specification file)
    Document d; ReadFileJSON(filename, d);
    if (d.IsNull())
        return;

    // Read top-level data
    assert(d.HasMember("Type"));
    assert(d.HasMember("Template"));
    assert(d.HasMember("Name"));

    // Create the suspension and wheel subsystems.
    assert(d.HasMember("Suspension"));

    std::string file_name = d["Suspension"]["Input File"].GetString();
    m_suspension = ReadSuspensionJSON(vehicle::GetDataFile(file_name));
    m_suspLoc = ReadVectorJSON(d["Suspension"]["Location"]);

    file_name = d["Suspension"]["Left Wheel Input File"].GetString();
    m_wheel[VehicleSide::LEFT] = ReadWheelJSON(vehicle::GetDataFile(file_name));
    file_name = d["Suspension"]["Right Wheel Input File"].GetString();
    m_wheel[VehicleSide::RIGHT] = ReadWheelJSON(vehicle::GetDataFile(file_name));

    // Read initial ride height (if specified)
    if (d.HasMember("Ride Height")) {
        m_ride_height = d["Ride Height"].GetDouble();
    } else {
        m_ride_height = -1;
    }

    // Read displacement limit
    assert(d.HasMember("Displacement Limit"));
    m_displ_limit = d["Displacement Limit"].GetDouble();

    // Create the steering subsystem, if specified
    if (d.HasMember("Steering")) {
        file_name = d["Steering"]["Input File"].GetString();
        m_steering = ReadSteeringJSON(vehicle::GetDataFile(file_name));
        m_steeringLoc = ReadVectorJSON(d["Steering"]["Location"]);
        m_steeringRot = ReadQuaternionJSON(d["Steering"]["Orientation"]);
    }

    // Create the anti-roll bar subsystem, if one exists.
    if (d["Suspension"].HasMember("Antirollbar Input File")) {
        file_name = d["Suspension"]["Antirollbar Input File"].GetString();
        m_antirollbar = ReadAntirollbarJSON(vehicle::GetDataFile(file_name));
        m_antirollbarLoc = ReadVectorJSON(d["Suspension"]["Antirollbar Location"]);
    }

    GetLog() << "Loaded JSON: " << filename.c_str() << "\n";

    m_tire[LEFT] = tire_left;
    m_tire[RIGHT] = tire_right;
}

ChSuspensionTestRig::~ChSuspensionTestRig() {
    delete m_csv;
}

void ChSuspensionTestRig::InitializeSubsystems() {
    // Create the chassis subsystem
    m_chassis = chrono_types::make_shared<TestRigChassis>();
    m_chassis->Initialize(m_system, ChCoordsys<>(), 0);
    m_chassis->SetFixed(true);

    // Create the terrain system
    m_terrain = std::unique_ptr<ChTerrain>(new TestRigTerrain);

    // Initialize the steering subsystem.
    if (m_steering)
        m_steering->Initialize(m_chassis, m_steeringLoc, m_steeringRot);

    // Initialize the suspension subsystem.
    m_suspension->Initialize(m_chassis, nullptr, m_steering, m_suspLoc);

    // Initialize the antirollbar subsystem.
    if (m_antirollbar)
        m_antirollbar->Initialize(m_chassis, m_suspension, m_antirollbarLoc);

    // Initialize the two wheels
    m_wheel[LEFT]->Initialize(m_suspension->GetSpindle(LEFT), LEFT);
    m_wheel[RIGHT]->Initialize(m_suspension->GetSpindle(RIGHT), RIGHT);

    // Associate tires to wheels
    m_wheel[LEFT]->SetTire(m_tire[LEFT]);
    m_wheel[RIGHT]->SetTire(m_tire[RIGHT]);

    // Initialize the tire subsystem
    m_tire[LEFT]->Initialize(m_wheel[LEFT]);
    m_tire[RIGHT]->Initialize(m_wheel[RIGHT]);

    // Imobilize wheels
}

void ChSuspensionTestRig::Initialize() {
    if (!m_driver) {
        throw ChException("No driver system provided");
    }

    // Initialize reference spindle vertical positions at design configuration.
    m_spindle_ref[LEFT] = m_suspension->GetSpindlePos(LEFT).z();
    m_spindle_ref[RIGHT] = m_suspension->GetSpindlePos(RIGHT).z();

    // Calculate displacement offset to set rig at specified ride height (if any).
    // The rig will be moved dynamically to this configuration over a time interval m_displ_delay.
    m_displ_offset = 0;
    m_displ_delay = 0;
    if (m_ride_height > 0) {
        m_displ_offset = CalcDisplacementOffset();
        m_displ_delay = 0.1;
    }

    // Set visualization modes
    m_suspension->SetVisualizationType(m_vis_suspension);
    if (m_steering)
        m_steering->SetVisualizationType(m_vis_steering);
    m_wheel[LEFT]->SetVisualizationType(m_vis_wheel);
    m_wheel[RIGHT]->SetVisualizationType(m_vis_wheel);
    m_tire[LEFT]->SetVisualizationType(m_vis_tire);
    m_tire[RIGHT]->SetVisualizationType(m_vis_tire);

    // Initialize the driver system
    m_driver->m_delay = m_displ_delay;
    m_driver->Initialize();
}

// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
void ChSuspensionTestRig::SetDriver(std::shared_ptr<ChDriverSTR> driver) {
    m_driver = driver;
}

// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
double ChSuspensionTestRig::GetMass() const {
    // Note: do not include mass of the wheels, as these are already accounted for in suspension.
    double mass = m_suspension->GetMass();
    if (m_steering)
        mass += m_steering->GetMass();

    return mass;
}

// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
TerrainForce ChSuspensionTestRig::ReportTireForce(VehicleSide side) const {
    return m_tire[side]->ReportTireForce(m_terrain.get());
}

ChSuspension::Force ChSuspensionTestRig::ReportSuspensionForce(VehicleSide side) const {
    return m_suspension->ReportSuspensionForce(side);
}

// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
double ChSuspensionTestRig::GetWheelTravel(VehicleSide side) const {
    if (GetChTime() < m_displ_delay)
        return 0;
    return m_suspension->GetSpindlePos(side).z() - m_spindle_ref[side];
}

// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
void ChSuspensionTestRig::Advance(double step) {
    double time = GetChTime();

    // Set actuator displacements
    double displ_left = 0;
    double displ_right = 0;
    double displ_speed_left = 0;
    double displ_speed_right = 0;

    if (time < m_displ_delay) {
        // Automatic phase to bring rig at specified initial ride height
        m_steering_input = 0;
        m_left_input = 0;
        m_right_input = 0;
        displ_left = m_displ_offset * time / m_displ_delay;
        displ_right = m_displ_offset * time / m_displ_delay;

        // Update spindle vertical reference positions
        m_spindle_ref[LEFT] = m_suspension->GetSpindlePos(LEFT).z();
        m_spindle_ref[RIGHT] = m_suspension->GetSpindlePos(RIGHT).z();
    } else {
        // Use actual driver inputs to set current actuator displacements
        m_steering_input = m_driver->GetSteering();
        m_left_input = m_driver->GetDisplacementLeft();
        m_right_input = m_driver->GetDisplacementRight();
        double left_input_speed = m_driver->GetDisplacementSpeedLeft();
        double right_input_speed = m_driver->GetDisplacementSpeedRight();

        displ_left = m_displ_offset + m_displ_limit * m_left_input;
        displ_right = m_displ_offset + m_displ_limit * m_right_input;
        displ_speed_left = m_displ_limit * left_input_speed;
        displ_speed_right = m_displ_limit * right_input_speed;
    }

    // Synchronize driver system
    m_driver->Synchronize(time);

    // Synchronize the tire subsystems
    m_tire[LEFT]->Synchronize(time, *m_terrain);
    m_tire[RIGHT]->Synchronize(time, *m_terrain);

    // Let the steering subsystem process the steering input
    if (m_steering) {
        m_steering->Synchronize(time, m_steering_input);
    }

    // Prepare suspension for accepting tire forces
    m_suspension->Synchronize();

    // Synchronize wheels (this applies tire forces to spindle bodies)
    for (auto wheel : m_wheel) {
        wheel->Synchronize();
    }

    // Update actuators
    UpdateActuators(displ_left, displ_speed_left, displ_right, displ_speed_right);

    // Update the height of the underlying terrain object, using the current z positions of the post bodies.
    static_cast<TestRigTerrain*>(m_terrain.get())->m_height_L = CalcTerrainHeight(LEFT);
    static_cast<TestRigTerrain*>(m_terrain.get())->m_height_R = CalcTerrainHeight(RIGHT);

    // Advance states of tire subsystems
    m_tire[LEFT]->Advance(step);
    m_tire[RIGHT]->Advance(step);

    // Invoke the base class method
    ChVehicle::Advance(step);

    // Generate output for plotting if requested
    time = GetChTime();
    if (!m_driver->Started()) {
        m_next_plot_output_time = time + m_plot_output_step;
    } else if (m_plot_output && time > m_next_plot_output_time) {
        CollectPlotData(time);
        m_next_plot_output_time += m_plot_output_step;
    }
}

// -----------------------------------------------------------------------------
// Log constraint violations
// -----------------------------------------------------------------------------
void ChSuspensionTestRig::LogConstraintViolations() {
    GetLog().SetNumFormat("%16.4e");

    // Report constraint violations for the suspension joints
    GetLog() << "\n---- LEFT side suspension constraint violations\n\n";
    m_suspension->LogConstraintViolations(LEFT);
    GetLog() << "\n---- RIGHT side suspension constraint violations\n\n";
    m_suspension->LogConstraintViolations(RIGHT);

    // Report constraint violations for the steering joints
    if (m_steering) {
        GetLog() << "\n---- STEERING constrain violations\n\n";
        m_steering->LogConstraintViolations();
    }

    GetLog().SetNumFormat("%g");
}

// -----------------------------------------------------------------------------

void ChSuspensionTestRig::SetSuspensionOutput(bool state) {
    m_suspension->SetOutput(state);
}

void ChSuspensionTestRig::SetSteeringOutput(bool state) {
    if (m_steering)
        m_steering->SetOutput(state);
}

void ChSuspensionTestRig::SetAntirollbarOutput(bool state) {
    if (m_antirollbar)
        m_antirollbar->SetOutput(state);
}

void ChSuspensionTestRig::Output(int frame, ChVehicleOutput& database) const {
    database.WriteTime(frame, m_system->GetChTime());

    if (m_suspension->OutputEnabled()) {
        database.WriteSection(m_suspension->GetName());
        m_suspension->Output(database);
    }

    if (m_steering && m_steering->OutputEnabled()) {
        database.WriteSection(m_steering->GetName());
        m_steering->Output(database);
    }

    if (m_antirollbar && m_antirollbar->OutputEnabled()) {
        database.WriteSection(m_antirollbar->GetName());
        m_antirollbar->Output(database);
    }
}

void ChSuspensionTestRig::SetPlotOutput(double output_step) {
    m_plot_output = true;
    m_plot_output_step = output_step;
    m_csv = new utils::CSV_writer(" ");
}

// =============================================================================
// ChSuspensionTestRigPlatform class implementation
// =============================================================================
ChSuspensionTestRigPlatform::ChSuspensionTestRigPlatform(
    ChWheeledVehicle& vehicle,           // vehicle source
    int axle_index,                      // index of test suspension
    int steering_index,                  // index of associated steering subsystem (-1 for no steering)
    double displ_limit,                  // limits for post displacement
    std::shared_ptr<ChTire> tire_left,   // left tire
    std::shared_ptr<ChTire> tire_right,  // right tire
    ChContactMethod contact_method       // contact method
    )
    : ChSuspensionTestRig(vehicle, axle_index, steering_index, displ_limit, tire_left, tire_right, contact_method) {
    InitializeSubsystems();
    Create();
}

ChSuspensionTestRigPlatform::ChSuspensionTestRigPlatform(
    const std::string& filename,         // JSON file with vehicle specification
    int axle_index,                      // index of the suspension to be tested
    double displ_limit,                  // limits for post displacement
    std::shared_ptr<ChTire> tire_left,   // left tire
    std::shared_ptr<ChTire> tire_right,  // right tire
    ChContactMethod contact_method       // contact method
    )
    : ChSuspensionTestRig(filename, axle_index, displ_limit, tire_left, tire_right, contact_method) {
    InitializeSubsystems();
    Create();
}

ChSuspensionTestRigPlatform::ChSuspensionTestRigPlatform(
    const std::string& filename,         // JSON file with test rig specification
    std::shared_ptr<ChTire> tire_left,   // left tire
    std::shared_ptr<ChTire> tire_right,  // right tire
    ChContactMethod contact_method       // contact method
    )
    : ChSuspensionTestRig(filename, tire_left, tire_right, contact_method) {
    InitializeSubsystems();
    Create();
}

void ChSuspensionTestRigPlatform::Create() {
    // Create a contact material for the two posts (shared)
    //// TODO: are default material properties ok?
    MaterialInfo minfo;
    auto post_mat = minfo.CreateMaterial(m_system->GetContactMethod());

    // Create the left post body (green)
    ChVector<> spindle_L_pos = m_suspension->GetSpindlePos(LEFT);
    ChVector<> post_L_pos = spindle_L_pos - ChVector<>(0, 0, m_tire[LEFT]->GetRadius());

    m_post[LEFT] = std::shared_ptr<ChBody>(m_system->NewBody());
    m_post[LEFT]->SetPos(post_L_pos);
    m_post[LEFT]->SetMass(100);
    m_post[LEFT]->SetCollide(true);
    m_system->Add(m_post[LEFT]);
    AddPostVisualization(LEFT, ChColor(0.1f, 0.8f, 0.15f));

    m_post[LEFT]->GetCollisionModel()->ClearModel();
    m_post[LEFT]->GetCollisionModel()->AddCylinder(post_mat, m_post_radius, m_post_radius, m_post_hheight,
                                                   ChVector<>(0, 0, -m_post_hheight),
                                                   ChMatrix33<>(Q_from_AngX(CH_C_PI / 2)));
    m_post[LEFT]->GetCollisionModel()->BuildModel();

    // Create the right post body (red)
    ChVector<> spindle_R_pos = m_suspension->GetSpindlePos(RIGHT);
    ChVector<> post_R_pos = spindle_R_pos - ChVector<>(0, 0, m_tire[RIGHT]->GetRadius());

    m_post[RIGHT] = std::shared_ptr<ChBody>(m_system->NewBody());
    m_post[RIGHT]->SetPos(post_R_pos);
    m_post[RIGHT]->SetMass(100);
    m_post[RIGHT]->SetCollide(true);
    m_system->Add(m_post[RIGHT]);
    AddPostVisualization(RIGHT, ChColor(0.8f, 0.1f, 0.1f));

    m_post[RIGHT]->GetCollisionModel()->ClearModel();
    m_post[RIGHT]->GetCollisionModel()->AddCylinder(post_mat, m_post_radius, m_post_radius, m_post_hheight,
                                                    ChVector<>(0, 0, -m_post_hheight),
                                                    ChMatrix33<>(Q_from_AngX(CH_C_PI / 2)));
    m_post[RIGHT]->GetCollisionModel()->BuildModel();

    // Create and initialize joints and actuators
    auto func_L = chrono_types::make_shared<ChFunction_Setpoint>();
    auto func_R = chrono_types::make_shared<ChFunction_Setpoint>();

    m_post_linact[LEFT] = chrono_types::make_shared<ChLinkMotorLinearPosition>();
    m_post_linact[LEFT]->SetNameString("L_post_linActuator");
    m_post_linact[LEFT]->SetMotionFunction(func_L);
    m_post_linact[LEFT]->Initialize(m_chassis->GetBody(), m_post[LEFT],
                                    ChFrame<>(ChVector<>(post_L_pos), Q_from_AngY(CH_C_PI_2)));
    m_system->AddLink(m_post_linact[LEFT]);

    m_post_linact[RIGHT] = chrono_types::make_shared<ChLinkMotorLinearPosition>();
    m_post_linact[RIGHT]->SetNameString("R_post_linActuator");
    m_post_linact[RIGHT]->SetMotionFunction(func_R);
    m_post_linact[RIGHT]->Initialize(m_chassis->GetBody(), m_post[RIGHT],
                                     ChFrame<>(ChVector<>(post_R_pos), Q_from_AngY(CH_C_PI_2)));
    m_system->AddLink(m_post_linact[RIGHT]);
}

void ChSuspensionTestRigPlatform::AddPostVisualization(VehicleSide side, const ChColor& color) {
    // Platform (on post body)
    auto base_cyl = chrono_types::make_shared<ChCylinderShape>();
    base_cyl->GetCylinderGeometry().rad = m_post_radius;
    base_cyl->GetCylinderGeometry().p1 = ChVector<>(0, 0, 0);
    base_cyl->GetCylinderGeometry().p2 = ChVector<>(0, 0, -2 * m_post_hheight);
    m_post[side]->AddAsset(base_cyl);

    auto col = chrono_types::make_shared<ChColorAsset>();
    col->SetColor(color);
    m_post[side]->AddAsset(col);

    // Piston (on post body)
    auto piston = chrono_types::make_shared<ChCylinderShape>();
    piston->GetCylinderGeometry().rad = m_post_radius / 6.0;
    piston->GetCylinderGeometry().p1 = ChVector<>(0, 0, -2 * m_post_hheight);
    piston->GetCylinderGeometry().p2 = ChVector<>(0, 0, -m_post_hheight * 20.0);
    m_post[side]->AddAsset(piston);

    // Post sleeve (on chassis/ground body)
    auto cyl = chrono_types::make_shared<ChCylinderShape>();
    cyl->GetCylinderGeometry().rad = m_post_radius / 4.0;
    cyl->GetCylinderGeometry().p1 = m_post[side]->GetPos() - ChVector<>(0, 0, 16 * m_post_hheight);
    cyl->GetCylinderGeometry().p2 = m_post[side]->GetPos() - ChVector<>(0, 0, 32 * m_post_hheight);
    m_chassis->GetBody()->AddAsset(cyl);
}

double ChSuspensionTestRigPlatform::CalcDisplacementOffset() {
    return -m_ride_height - m_post[LEFT]->GetPos().z();
}

double ChSuspensionTestRigPlatform::CalcTerrainHeight(VehicleSide side) {
    // Update the height of the underlying terrain object, using the current z positions of the post bodies.
    return m_post[side]->GetPos().z();
}

void ChSuspensionTestRigPlatform::UpdateActuators(double displ_left,
                                                  double displ_speed_left,
                                                  double displ_right,
                                                  double displ_speed_right) {
    auto func_L = std::static_pointer_cast<ChFunction_Setpoint>(m_post_linact[LEFT]->GetMotionFunction());
    auto func_R = std::static_pointer_cast<ChFunction_Setpoint>(m_post_linact[RIGHT]->GetMotionFunction());
    func_L->SetSetpointAndDerivatives(displ_left, displ_speed_left, 0.0);
    func_R->SetSetpointAndDerivatives(displ_right, displ_speed_right, 0.0);
}

double ChSuspensionTestRigPlatform::GetActuatorDisp(VehicleSide side) {
    double time = GetSystem()->GetChTime();
    return m_post_linact[side]->GetMotionFunction()->Get_y(time);
}

double ChSuspensionTestRigPlatform::GetActuatorForce(VehicleSide side) {
    return m_post_linact[side]->Get_react_force().x();
}

double ChSuspensionTestRigPlatform::GetRideHeight() const {
    // Note: the chassis reference frame is constructed at a height of 0.
    return -(m_post[LEFT]->GetPos().z() + m_post[RIGHT]->GetPos().z()) / 2;
}

void ChSuspensionTestRigPlatform::CollectPlotData(double time) {
    // Suspension forces
    auto frc_left = ReportSuspensionForce(LEFT);
    auto frc_right = ReportSuspensionForce(RIGHT);

    // Tire forces
    auto tire_force_L = ReportTireForce(VehicleSide::LEFT);
    auto tire_force_R = ReportTireForce(VehicleSide::RIGHT);

    // Tire camber angles (flip sign of reported camber angle on the left to get common definition)
    double gamma_L = -m_tire[LEFT]->GetCamberAngle() * CH_C_RAD_TO_DEG;
    double gamma_R = m_tire[RIGHT]->GetCamberAngle() * CH_C_RAD_TO_DEG;

    *m_csv << time;

    *m_csv << GetLeftInput() << GetSpindlePos(LEFT).z() << GetSpindleLinVel(LEFT).z() << GetWheelTravel(LEFT);
    *m_csv << frc_left.spring_force << frc_left.shock_force;

    *m_csv << GetRightInput() << GetSpindlePos(RIGHT).z() << GetSpindleLinVel(RIGHT).z() << GetWheelTravel(RIGHT);
    *m_csv << frc_right.spring_force << frc_right.shock_force;

    *m_csv << GetRideHeight() << gamma_L << gamma_R;

    *m_csv << tire_force_L.point << tire_force_L.force << tire_force_L.moment;
    *m_csv << tire_force_R.point << tire_force_R.force << tire_force_R.moment;

    *m_csv << std::endl;
}

void ChSuspensionTestRigPlatform::PlotOutput(const std::string& out_dir, const std::string& out_name) {
    if (!m_plot_output)
        return;

    std::string out_file = out_dir + "/" + out_name + ".txt";
    m_csv->write_to_file(out_file);

#ifdef CHRONO_POSTPROCESS
    std::string gplfile = out_dir + "/tmp.gpl";
    postprocess::ChGnuPlot mplot(gplfile.c_str());

    std::string title = "Suspension test rig - Spring forces";
    mplot.OutputWindow(0);
    mplot.SetTitle(title.c_str());
    mplot.SetLabelX("wheel travel [m]");
    mplot.SetLabelY("spring force [N]");
    mplot.SetCommand("set format y '%4.1e'");
    mplot.SetCommand("set terminal wxt size 800, 600");
    mplot.Plot(out_file.c_str(), 5, 6, "left", " with lines lw 2");
    mplot.Plot(out_file.c_str(), 11, 12, "right", " with lines lw 2");

    title = "Suspension test rig - Shock forces";
    mplot.OutputWindow(1);
    mplot.SetTitle(title.c_str());
    mplot.SetLabelX("wheel veertical speed [m/s]");
    mplot.SetLabelY("shock force [N]");
    mplot.SetCommand("set format y '%4.1e'");
    mplot.SetCommand("set terminal wxt size 800, 600");
    mplot.Plot(out_file.c_str(), 4, 7, "left", " with lines lw 2");
    mplot.Plot(out_file.c_str(), 10, 13, "right", " with lines lw 2");

    title = "Suspension test rig - Camber angle";
    mplot.OutputWindow(2);
    mplot.SetTitle(title.c_str());
    mplot.SetLabelX("wheel travel [m]");
    mplot.SetLabelY("camber angle [deg]");
    mplot.SetCommand("set format y '%4.1f'");
    mplot.SetCommand("set terminal wxt size 800, 600");
    mplot.Plot(out_file.c_str(), 5, 15, "left", " with lines lw 2");
    mplot.Plot(out_file.c_str(), 11, 16, "right", " with lines lw 2");
#endif
}

// =============================================================================
// ChSuspensionTestRigPushrod class implementation
// =============================================================================
ChSuspensionTestRigPushrod::ChSuspensionTestRigPushrod(
    ChWheeledVehicle& vehicle,           // vehicle source
    int axle_index,                      // index of test suspension
    int steering_index,                  // index of associated steering subsystem (-1 for no steering)
    double displ_limit,                  // limits for post displacement
    std::shared_ptr<ChTire> tire_left,   // left tire
    std::shared_ptr<ChTire> tire_right,  // right tire
    ChContactMethod contact_method       // contact method
    )
    : ChSuspensionTestRig(vehicle, axle_index, steering_index, displ_limit, tire_left, tire_right, contact_method) {
    InitializeSubsystems();
    Create();
}

ChSuspensionTestRigPushrod::ChSuspensionTestRigPushrod(
    const std::string& filename,         // JSON file with vehicle specification
    int axle_index,                      // index of the suspension to be tested
    double displ_limit,                  // limits for post displacement
    std::shared_ptr<ChTire> tire_left,   // left tire
    std::shared_ptr<ChTire> tire_right,  // right tire
    ChContactMethod contact_method       // contact method
    )
    : ChSuspensionTestRig(filename, axle_index, displ_limit, tire_left, tire_right, contact_method) {
    InitializeSubsystems();
    Create();
}

ChSuspensionTestRigPushrod::ChSuspensionTestRigPushrod(
    const std::string& filename,         // JSON file with test rig specification
    std::shared_ptr<ChTire> tire_left,   // left tire
    std::shared_ptr<ChTire> tire_right,  // right tire
    ChContactMethod contact_method       // contact method
    )
    : ChSuspensionTestRig(filename, tire_left, tire_right, contact_method) {
    InitializeSubsystems();
    Create();
}

void ChSuspensionTestRigPushrod::Create() {
    // Create and initialize the linear actuators.
    // These connect the spindle centers with ground points directly below the spindles at the initial configuration.
    auto func_L = chrono_types::make_shared<ChFunction_Setpoint>();
    auto func_R = chrono_types::make_shared<ChFunction_Setpoint>();

    auto pos_sL = m_suspension->GetSpindle(LEFT)->GetCoord();
    auto pos_sR = m_suspension->GetSpindle(RIGHT)->GetCoord();

    auto pos_gL = pos_sL;
    auto pos_gR = pos_sR;
    pos_gL.pos.z() = -m_rod_length;
    pos_gR.pos.z() = -m_rod_length;

    m_rod_linact[LEFT] = chrono_types::make_shared<ChLinkLinActuator>();
    m_rod_linact[LEFT]->SetNameString("L_rod_actuator");
    m_rod_linact[LEFT]->Set_dist_funct(func_L);
    m_rod_linact[LEFT]->Initialize(m_chassis->GetBody(), m_suspension->GetSpindle(LEFT), false, pos_gL, pos_sL);
    m_system->AddLink(m_rod_linact[LEFT]);

    m_rod_linact[RIGHT] = chrono_types::make_shared<ChLinkLinActuator>();
    m_rod_linact[RIGHT]->SetNameString("R_rod_actuator");
    m_rod_linact[RIGHT]->Set_dist_funct(func_R);
    m_rod_linact[RIGHT]->Initialize(m_chassis->GetBody(), m_suspension->GetSpindle(RIGHT), false, pos_gR, pos_sR);
    m_system->AddLink(m_rod_linact[RIGHT]);

    m_rod_linact[LEFT]->Set_lin_offset(m_rod_length);
    m_rod_linact[RIGHT]->Set_lin_offset(m_rod_length);

    // Create the two rod bodies (used only for visualization)
    m_rod[LEFT] = std::shared_ptr<ChBody>(m_system->NewBody());
    m_rod[LEFT]->SetPos(pos_sL.pos);
    m_rod[LEFT]->SetBodyFixed(true);
    m_system->Add(m_rod[LEFT]);
    AddRodVisualization(LEFT, ChColor(0.1f, 0.8f, 0.15f));

    m_rod[RIGHT] = std::shared_ptr<ChBody>(m_system->NewBody());
    m_rod[RIGHT]->SetPos(pos_sR.pos);
    m_rod[RIGHT]->SetBodyFixed(true);
    m_system->Add(m_rod[RIGHT]);
    AddRodVisualization(RIGHT, ChColor(0.8f, 0.1f, 0.1f));
}

void ChSuspensionTestRigPushrod::AddRodVisualization(VehicleSide side, const ChColor& color) {
    auto cyl = chrono_types::make_shared<ChCylinderShape>();
    cyl->GetCylinderGeometry().p1 = ChVector<>(0, 0, 0);
    cyl->GetCylinderGeometry().p2 = ChVector<>(0, 0, -m_rod_length);
    cyl->GetCylinderGeometry().rad = m_rod_radius;
    m_rod[side]->AddAsset(cyl);
    m_rod[side]->AddAsset(chrono_types::make_shared<ChColorAsset>(color));
}

double ChSuspensionTestRigPushrod::CalcDisplacementOffset() {
    // Set initial spindle position based on tire radius (note: tire assumed rigid here)
    return m_tire[LEFT]->GetRadius() - m_ride_height;
}

double ChSuspensionTestRigPushrod::CalcTerrainHeight(VehicleSide side) {
    // No terrain used here
    return -1000;
}

void ChSuspensionTestRigPushrod::UpdateActuators(double displ_left,
                                                 double displ_speed_left,
                                                 double displ_right,
                                                 double displ_speed_right) {
    auto func_L = std::static_pointer_cast<ChFunction_Setpoint>(m_rod_linact[LEFT]->Get_dist_funct());
    auto func_R = std::static_pointer_cast<ChFunction_Setpoint>(m_rod_linact[RIGHT]->Get_dist_funct());
    func_L->SetSetpointAndDerivatives(displ_left, displ_speed_left, 0.0);
    func_R->SetSetpointAndDerivatives(displ_right, displ_speed_right, 0.0);

    // Move the rod visualization bodies
    m_rod[LEFT]->SetPos(m_suspension->GetSpindle(LEFT)->GetPos());
    m_rod[RIGHT]->SetPos(m_suspension->GetSpindle(RIGHT)->GetPos());
}

double ChSuspensionTestRigPushrod::GetActuatorDisp(VehicleSide side) {
    double time = GetSystem()->GetChTime();
    return m_rod_linact[side]->Get_dist_funct()->Get_y(time);
}

double ChSuspensionTestRigPushrod::GetActuatorForce(VehicleSide side) {
    //// TODO
    ////ChVector<> react = m_rod_linact[side]->Get_react_force();
    return 0;
}

double ChSuspensionTestRigPushrod::GetRideHeight() const {
    // Estimated from average spindle positions and tire radius (note: tire assumed rigid here)
    auto spindle_avg =
        (m_suspension->GetSpindle(LEFT)->GetPos().z() + m_suspension->GetSpindle(RIGHT)->GetPos().z()) / 2;
    return m_tire[LEFT]->GetRadius() - spindle_avg;
}

void ChSuspensionTestRigPushrod::CollectPlotData(double time) {
    // Suspension forces
    auto frc_left = ReportSuspensionForce(LEFT);
    auto frc_right = ReportSuspensionForce(RIGHT);

    // Tire camber angles (flip sign of reported camber angle on the left to get common definition)
    double gamma_L = -m_tire[LEFT]->GetCamberAngle() * CH_C_RAD_TO_DEG;
    double gamma_R = m_tire[RIGHT]->GetCamberAngle() * CH_C_RAD_TO_DEG;

    *m_csv << time;

    *m_csv << GetLeftInput() << GetSpindlePos(LEFT).z() << GetSpindleLinVel(LEFT).z() << GetWheelTravel(LEFT);
    *m_csv << frc_left.spring_force << frc_left.shock_force;

    *m_csv << GetRightInput() << GetSpindlePos(RIGHT).z() << GetSpindleLinVel(RIGHT).z() << GetWheelTravel(RIGHT);
    *m_csv << frc_right.spring_force << frc_right.shock_force;

    *m_csv << GetRideHeight() << gamma_L << gamma_R;

    *m_csv << std::endl;
}

void ChSuspensionTestRigPushrod::PlotOutput(const std::string& out_dir, const std::string& out_name) {
    if (!m_plot_output)
        return;

    std::string out_file = out_dir + "/" + out_name + ".txt";
    m_csv->write_to_file(out_file);

#ifdef CHRONO_POSTPROCESS
    std::string gplfile = out_dir + "/tmp.gpl";
    postprocess::ChGnuPlot mplot(gplfile.c_str());

    std::string title = "Suspension test rig - Spring forces";
    mplot.OutputWindow(0);
    mplot.SetTitle(title.c_str());
    mplot.SetLabelX("wheel travel [m]");
    mplot.SetLabelY("spring force [N]");
    mplot.SetCommand("set format y '%4.1e'");
    mplot.SetCommand("set terminal wxt size 800, 600");
    mplot.Plot(out_file.c_str(), 5, 6, "left", " with lines lw 2");
    mplot.Plot(out_file.c_str(), 11, 12, "right", " with lines lw 2");

    title = "Suspension test rig - Shock forces";
    mplot.OutputWindow(1);
    mplot.SetTitle(title.c_str());
    mplot.SetLabelX("wheel veertical speed [m/s]");
    mplot.SetLabelY("shock force [N]");
    mplot.SetCommand("set format y '%4.1e'");
    mplot.SetCommand("set terminal wxt size 800, 600");
    mplot.Plot(out_file.c_str(), 4, 7, "left", " with lines lw 2");
    mplot.Plot(out_file.c_str(), 10, 13, "right", " with lines lw 2");

    title = "Suspension test rig - Camber angle";
    mplot.OutputWindow(2);
    mplot.SetTitle(title.c_str());
    mplot.SetLabelX("wheel travel [m]");
    mplot.SetLabelY("camber angle [deg]");
    mplot.SetCommand("set format y '%4.1f'");
    mplot.SetCommand("set terminal wxt size 800, 600");
    mplot.Plot(out_file.c_str(), 5, 15, "left", " with lines lw 2");
    mplot.Plot(out_file.c_str(), 11, 16, "right", " with lines lw 2");
#endif
}

}  // end namespace vehicle
}  // end namespace chrono


text:
angular.module('starter.services', [])

.factory('SocketIO', function() {
  return io();
})

.factory('Question', function($resource) {
  return $resource('/resource/questions/:questionId', null, {
    'activate': {
      method: 'POST',
      url: '/resource/questions/:questionId/activate'
    },
    'next': {
      method: 'POST',
      url: '/resource/questions/:questionId/next'
    }
  });
})

.factory('Answer', function($resource) {
  return $resource('/resource/answers/:answerId', null, {
    'leaders': {
      method: 'GET',
      url: '/resource/leaders',
      isArray: true
    },
    'truncate': {
      method: 'DELETE',
      url: '/resource/leaders'
    }
  });
})

.factory('AuthenticationService', function() {
  var auth = {
    isAuthenticated: false,
    isAdmin: false
  }

  return auth;
})

.factory('TokenInterceptor', function($q, $window, $location, AuthenticationService) {
  return {
    request: function(config) {
      config.headers = config.headers || {};
      if ($window.localStorage.token) {
        config.headers.Authorization = 'Bearer ' + $window.localStorage.token;
      }
      return config;
    },

    requestError: function(rejection) {
      return $q.reject(rejection);
    },

    /* Set Authentication.isAuthenticated to true if 200 received */
    response: function(response) {
      if (response != null && response.status == 200 && $window.localStorage.token && !AuthenticationService.isAuthenticated) {
        AuthenticationService.isAuthenticated = true;
      }
      return response || $q.when(response);
    },

    /* Revoke client authentication if 401 is received */
    responseError: function(rejection) {
      if (rejection != null && rejection.status === 401 && ($window.localStorage.token || AuthenticationService.isAuthenticated)) {
        delete $window.localStorage.token;
        AuthenticationService.isAuthenticated = false;
        $location.path("/register");
      }

      return $q.reject(rejection);
    }
  };
})

.factory('RegistrationService', function($window, $http, $ionicPopup, $rootScope, AuthenticationService) {
  return {
    login: function(email, password) {
      return $http.post('/login', {
        email: email,
        password: password
      }).then(function(result) {
        $rootScope.user = result.data;
        console.log(result.data);
        AuthenticationService.isAuthenticated = true;
        AuthenticationService.isAdmin = result.data.is_admin;

        $window.sessionStorage.name     = result.data.name;
        $window.sessionStorage.is_admin = result.data.is_admin;
        $window.localStorage.token      = result.data.token;
      }).catch(function(err) {
        $ionicPopup.alert({
          title: 'Failed',
          content: err.data
        });
      });;
    },

    logout: function() {
      delete $window.localStorage.token;
    },

    register: function(user) {
      return $http.post('/register', user).then(function(result) {
        $rootScope.user = result.data;
        AuthenticationService.isAuthenticated = true;
        $window.sessionStorage.name     = result.data.name;
        $window.sessionStorage.is_admin = result.data.is_admin;
        $window.localStorage.token      = result.data.token;
        console.log(result.data);
      }).catch(function(err) {
        $ionicPopup.alert({
          title: 'Failed',
          content: err.data
        });
      });
    }
  }
})

.factory('UserResponse', function() {
  var storageKey = 'userResponses';

  var localGet = function() {
    var ret = localStorage.getItem(storageKey);
    if (ret === null) {
      ret = {};
    } else {
      ret = JSON.parse(ret);
    }
    return ret;
  };

  var localSet = function(val) {
    localStorage.setItem(storageKey, JSON.stringify(val));
  };

  return {
    set: function(key, value) {
      var answers = localGet();
      answers[key] = value;
      localSet(answers);
    },

    get: function(key) {
      var answers = localGet();
      return answers[key];
    },

    reset: function() {
      localStorage.removeItem(storageKey);
    }
  };
})


text:
package org.coursera.androidcapstone.symptom.oauth;

import retrofit.RequestInterceptor;

import com.google.common.io.BaseEncoding;

public class OAuth2RequestInterceptor implements RequestInterceptor {

    private final String username;
    private final String password;
    private OAuth2Response oauth2Response;

    public OAuth2RequestInterceptor(final String username, final String password) {
		this.username = username;
		this.password = password;
		this.oauth2Response = null;
	}

    @Override
    public void intercept(RequestFacade requestFacade) {
        if (oauth2Response == null) {
            requestFacade.addHeader("Authorization", "Basic " + BaseEncoding.base64().encode((username + ":" + password).getBytes()));
        }
        else {
        	requestFacade.addHeader("Authorization", "Bearer " + oauth2Response.getAccessToken());
        }
    }

    ///

	public String getUsername() {
		return username;
	}

	public String getPassword() {
		return password;
	}

	public OAuth2Response getOAuth2Response() {
		return oauth2Response;
	}

	public void setOAuth2Response(OAuth2Response oauth2Response) {
		this.oauth2Response = oauth2Response;
	}
}


text:
import MediaOverlay from './MediaOverlay';
import Registry from '@ui-autotools/registry';

const metadata = Registry.getComponentMetadata(MediaOverlay);

metadata.exportInfo = {
  path: 'src/MediaOverlay/MediaOverlay.js',
};