{
    _startupScriptFilename = startupScriptFile;
    std::replace(_startupScriptFilename.begin(), _startupScriptFilename.end(), '\\', '/');
}

/****************************************************************************

http://www.cocos2d-x.org

****************************************************************************/
#include "CCApplication.h"
#include "CCEGLView.h"
#include "CCDirector.h"
#include <algorithm>
#include "platform/CCFileUtils.h"
/**
@brief    This function change the PVRFrame show/hide setting in register.
@param  bEnable If true show the PVRFrame window, otherwise hide.
*/
static void PVRFrameEnableControlWindow(bool bEnable);

NS_CC_BEGIN

// sharedApplication pointer
Application * Application::sm_pSharedApplication = 0;

Application::Application()
: _instance(NULL)
, _accelTable(NULL)
{
    _instance    = GetModuleHandle(NULL);
    _animationInterval.QuadPart = 0;
    CC_ASSERT(! sm_pSharedApplication);
    sm_pSharedApplication = this;
}

Application::~Application()
{
    CC_ASSERT(this == sm_pSharedApplication);
    sm_pSharedApplication = NULL;
}

int Application::run()
{
    PVRFrameEnableControlWindow(false);

    // Main message loop:
    LARGE_INTEGER nFreq;
    LARGE_INTEGER nLast;
    LARGE_INTEGER nNow;

    QueryPerformanceFrequency(&nFreq);
    QueryPerformanceCounter(&nLast);

    // Initialize instance and cocos2d.
    if (!applicationDidFinishLaunching())
    {
        return 0;
    }

    EGLView* pMainWnd = EGLView::getInstance();

    while(!pMainWnd->windowShouldClose())
    {
        QueryPerformanceCounter(&nNow);
        if (nNow.QuadPart - nLast.QuadPart > _animationInterval.QuadPart)
        {
            nLast.QuadPart = nNow.QuadPart;
            Director::getInstance()->mainLoop();
            pMainWnd->pollEvents();
        }
        else
        {
            Sleep(0);
        }
    }

    /* Only work on Desktop
    *  Director::mainLoop is really one frame logic
    *  when we want to close the window, we should call Director::end();
    *  then call Director::mainLoop to do release of internal resources
    */
    Director::getInstance()->end();
    Director::getInstance()->mainLoop();
    return true;
}

void Application::setAnimationInterval(double interval)
{
    LARGE_INTEGER nFreq;
    QueryPerformanceFrequency(&nFreq);
    _animationInterval.QuadPart = (LONGLONG)(interval * nFreq.QuadPart);
}

// static member function
Application* Application::getInstance()
{
    CC_ASSERT(sm_pSharedApplication);
    return sm_pSharedApplication;
}

// @deprecated Use getInstance() instead
Application* Application::sharedApplication()
{
    return Application::getInstance();
}

LanguageType Application::getCurrentLanguage()
{
    LanguageType ret = LanguageType::ENGLISH;

    LCID localeID = GetUserDefaultLCID();
    unsigned short primaryLanguageID = localeID & 0xFF;

    switch (primaryLanguageID)
    {
        case LANG_CHINESE:
            ret = LanguageType::CHINESE;
            break;
        case LANG_ENGLISH:
            ret = LanguageType::ENGLISH;
            break;
        case LANG_FRENCH:
            ret = LanguageType::FRENCH;
            break;
        case LANG_ITALIAN:
            ret = LanguageType::ITALIAN;
            break;
        case LANG_GERMAN:
            ret = LanguageType::GERMAN;
            break;
        case LANG_SPANISH:
            ret = LanguageType::SPANISH;
            break;
        case LANG_RUSSIAN:
            ret = LanguageType::RUSSIAN;
            break;
        case LANG_KOREAN:
            ret = LanguageType::KOREAN;
            break;
        case LANG_JAPANESE:
            ret = LanguageType::JAPANESE;
            break;
        case LANG_HUNGARIAN:
            ret = LanguageType::HUNGARIAN;
            break;
        case LANG_PORTUGUESE:
            ret = LanguageType::PORTUGUESE;
            break;
        case LANG_ARABIC:
            ret = LanguageType::ARABIC;
            break;
	    case LANG_NORWEGIAN:
            ret = LanguageType::NORWEGIAN;
            break;
 	    case LANG_POLISH:
            ret = LanguageType::POLISH;
            break;
    }

    return ret;
}

Application::Platform Application::getTargetPlatform()
{
    return Platform::OS_WINDOWS;
}

void Application::setResourceRootPath(const std::string& rootResDir)
{
    _resourceRootPath = rootResDir;
    std::replace(_resourceRootPath.begin(), _resourceRootPath.end(), '\\', '/');
    if (_resourceRootPath[_resourceRootPath.length() - 1] != '/')
    {
        _resourceRootPath += '/';
    }
    FileUtils* pFileUtils = FileUtils::getInstance();
    std::vector<std::string> searchPaths = pFileUtils->getSearchPaths();
    searchPaths.insert(searchPaths.begin(), _resourceRootPath);
    pFileUtils->setSearchPaths(searchPaths);
}

const std::string& Application::getResourceRootPath(void)
{
    return _resourceRootPath;
}

void Application::setStartupScriptFilename(const std::string& startupScriptFile)

NS_CC_END

// Local function
static void PVRFrameEnableControlWindow(bool bEnable)
{
    HKEY hKey = 0;

    // Open PVRFrame control key, if not exist create it.
    if(ERROR_SUCCESS != RegCreateKeyExW(HKEY_CURRENT_USER,
        L"Software\\Imagination Technologies\\PVRVFRame\\STARTUP\\",
        0,
        0,
        REG_OPTION_NON_VOLATILE,
        KEY_ALL_ACCESS,
        0,
        &hKey,
        NULL))
    {
        return;
    }

    const WCHAR* wszValue = L"hide_gui";
    const WCHAR* wszNewData = (bEnable) ? L"NO" : L"YES";
    WCHAR wszOldData[256] = {0};
    DWORD   dwSize = sizeof(wszOldData);
    LSTATUS status = RegQueryValueExW(hKey, wszValue, 0, NULL, (LPBYTE)wszOldData, &dwSize);
    if (ERROR_FILE_NOT_FOUND == status              // the key not exist
        || (ERROR_SUCCESS == status                 // or the hide_gui value is exist
        && 0 != wcscmp(wszNewData, wszOldData)))    // but new data and old data not equal
    {
        dwSize = sizeof(WCHAR) * (wcslen(wszNewData) + 1);
        RegSetValueEx(hKey, wszValue, 0, REG_SZ, (const BYTE *)wszNewData, dwSize);
    }

    RegCloseKey(hKey);
}


Application* Application::getInstance()
{
    CC_ASSERT(sm_pSharedApplication);
    return sm_pSharedApplication;
}

/****************************************************************************

http://www.cocos2d-x.org

****************************************************************************/
#include "CCApplication.h"
#include "CCEGLView.h"
#include "CCDirector.h"
#include <algorithm>
#include "platform/CCFileUtils.h"
/**
@brief    This function change the PVRFrame show/hide setting in register.
@param  bEnable If true show the PVRFrame window, otherwise hide.
*/
static void PVRFrameEnableControlWindow(bool bEnable);

NS_CC_BEGIN

// sharedApplication pointer
Application * Application::sm_pSharedApplication = 0;

Application::Application()
: _instance(NULL)
, _accelTable(NULL)
{
    _instance    = GetModuleHandle(NULL);
    _animationInterval.QuadPart = 0;
    CC_ASSERT(! sm_pSharedApplication);
    sm_pSharedApplication = this;
}

Application::~Application()
{
    CC_ASSERT(this == sm_pSharedApplication);
    sm_pSharedApplication = NULL;
}

int Application::run()
{
    PVRFrameEnableControlWindow(false);

    // Main message loop:
    LARGE_INTEGER nFreq;
    LARGE_INTEGER nLast;
    LARGE_INTEGER nNow;

    QueryPerformanceFrequency(&nFreq);
    QueryPerformanceCounter(&nLast);

    // Initialize instance and cocos2d.
    if (!applicationDidFinishLaunching())
    {
        return 0;
    }

    EGLView* pMainWnd = EGLView::getInstance();

    while(!pMainWnd->windowShouldClose())
    {
        QueryPerformanceCounter(&nNow);
        if (nNow.QuadPart - nLast.QuadPart > _animationInterval.QuadPart)
        {
            nLast.QuadPart = nNow.QuadPart;
            Director::getInstance()->mainLoop();
            pMainWnd->pollEvents();
        }
        else
        {
            Sleep(0);
        }
    }

    /* Only work on Desktop
    *  Director::mainLoop is really one frame logic
    *  when we want to close the window, we should call Director::end();
    *  then call Director::mainLoop to do release of internal resources
    */
    Director::getInstance()->end();
    Director::getInstance()->mainLoop();
    return true;
}

void Application::setAnimationInterval(double interval)
{
    LARGE_INTEGER nFreq;
    QueryPerformanceFrequency(&nFreq);
    _animationInterval.QuadPart = (LONGLONG)(interval * nFreq.QuadPart);
}

// static member function

// @deprecated Use getInstance() instead
Application* Application::sharedApplication()
{
    return Application::getInstance();
}

LanguageType Application::getCurrentLanguage()
{
    LanguageType ret = LanguageType::ENGLISH;

    LCID localeID = GetUserDefaultLCID();
    unsigned short primaryLanguageID = localeID & 0xFF;

    switch (primaryLanguageID)
    {
        case LANG_CHINESE:
            ret = LanguageType::CHINESE;
            break;
        case LANG_ENGLISH:
            ret = LanguageType::ENGLISH;
            break;
        case LANG_FRENCH:
            ret = LanguageType::FRENCH;
            break;
        case LANG_ITALIAN:
            ret = LanguageType::ITALIAN;
            break;
        case LANG_GERMAN:
            ret = LanguageType::GERMAN;
            break;
        case LANG_SPANISH:
            ret = LanguageType::SPANISH;
            break;
        case LANG_RUSSIAN:
            ret = LanguageType::RUSSIAN;
            break;
        case LANG_KOREAN:
            ret = LanguageType::KOREAN;
            break;
        case LANG_JAPANESE:
            ret = LanguageType::JAPANESE;
            break;
        case LANG_HUNGARIAN:
            ret = LanguageType::HUNGARIAN;
            break;
        case LANG_PORTUGUESE:
            ret = LanguageType::PORTUGUESE;
            break;
        case LANG_ARABIC:
            ret = LanguageType::ARABIC;
            break;
	    case LANG_NORWEGIAN:
            ret = LanguageType::NORWEGIAN;
            break;
 	    case LANG_POLISH:
            ret = LanguageType::POLISH;
            break;
    }

    return ret;
}

Application::Platform Application::getTargetPlatform()
{
    return Platform::OS_WINDOWS;
}

void Application::setResourceRootPath(const std::string& rootResDir)
{
    _resourceRootPath = rootResDir;
    std::replace(_resourceRootPath.begin(), _resourceRootPath.end(), '\\', '/');
    if (_resourceRootPath[_resourceRootPath.length() - 1] != '/')
    {
        _resourceRootPath += '/';
    }
    FileUtils* pFileUtils = FileUtils::getInstance();
    std::vector<std::string> searchPaths = pFileUtils->getSearchPaths();
    searchPaths.insert(searchPaths.begin(), _resourceRootPath);
    pFileUtils->setSearchPaths(searchPaths);
}

const std::string& Application::getResourceRootPath(void)
{
    return _resourceRootPath;
}

void Application::setStartupScriptFilename(const std::string& startupScriptFile)
{
    _startupScriptFilename = startupScriptFile;
    std::replace(_startupScriptFilename.begin(), _startupScriptFilename.end(), '\\', '/');
}

NS_CC_END

// Local function
static void PVRFrameEnableControlWindow(bool bEnable)
{
    HKEY hKey = 0;

    // Open PVRFrame control key, if not exist create it.
    if(ERROR_SUCCESS != RegCreateKeyExW(HKEY_CURRENT_USER,
        L"Software\\Imagination Technologies\\PVRVFRame\\STARTUP\\",
        0,
        0,
        REG_OPTION_NON_VOLATILE,
        KEY_ALL_ACCESS,
        0,
        &hKey,
        NULL))
    {
        return;
    }

    const WCHAR* wszValue = L"hide_gui";
    const WCHAR* wszNewData = (bEnable) ? L"NO" : L"YES";
    WCHAR wszOldData[256] = {0};
    DWORD   dwSize = sizeof(wszOldData);
    LSTATUS status = RegQueryValueExW(hKey, wszValue, 0, NULL, (LPBYTE)wszOldData, &dwSize);
    if (ERROR_FILE_NOT_FOUND == status              // the key not exist
        || (ERROR_SUCCESS == status                 // or the hide_gui value is exist
        && 0 != wcscmp(wszNewData, wszOldData)))    // but new data and old data not equal
    {
        dwSize = sizeof(WCHAR) * (wcslen(wszNewData) + 1);
        RegSetValueEx(hKey, wszValue, 0, REG_SZ, (const BYTE *)wszNewData, dwSize);
    }

    RegCloseKey(hKey);
}


while(!pMainWnd->windowShouldClose())
    {
        QueryPerformanceCounter(&nNow);
        if (nNow.QuadPart - nLast.QuadPart > _animationInterval.QuadPart)
        {
            nLast.QuadPart = nNow.QuadPart;
            Director::getInstance()->mainLoop();
            pMainWnd->pollEvents();
        }
        else
        {
            Sleep(0);
        }
    }

/****************************************************************************

http://www.cocos2d-x.org

****************************************************************************/
#include "CCApplication.h"
#include "CCEGLView.h"
#include "CCDirector.h"
#include <algorithm>
#include "platform/CCFileUtils.h"
/**
@brief    This function change the PVRFrame show/hide setting in register.
@param  bEnable If true show the PVRFrame window, otherwise hide.
*/
static void PVRFrameEnableControlWindow(bool bEnable);

NS_CC_BEGIN

// sharedApplication pointer
Application * Application::sm_pSharedApplication = 0;

Application::Application()
: _instance(NULL)
, _accelTable(NULL)
{
    _instance    = GetModuleHandle(NULL);
    _animationInterval.QuadPart = 0;
    CC_ASSERT(! sm_pSharedApplication);
    sm_pSharedApplication = this;
}

Application::~Application()
{
    CC_ASSERT(this == sm_pSharedApplication);
    sm_pSharedApplication = NULL;
}

int Application::run()
{
    PVRFrameEnableControlWindow(false);

    // Main message loop:
    LARGE_INTEGER nFreq;
    LARGE_INTEGER nLast;
    LARGE_INTEGER nNow;

    QueryPerformanceFrequency(&nFreq);
    QueryPerformanceCounter(&nLast);

    // Initialize instance and cocos2d.
    if (!applicationDidFinishLaunching())
    {
        return 0;
    }

    EGLView* pMainWnd = EGLView::getInstance();

    /* Only work on Desktop
    *  Director::mainLoop is really one frame logic
    *  when we want to close the window, we should call Director::end();
    *  then call Director::mainLoop to do release of internal resources
    */
    Director::getInstance()->end();
    Director::getInstance()->mainLoop();
    return true;
}

void Application::setAnimationInterval(double interval)
{
    LARGE_INTEGER nFreq;
    QueryPerformanceFrequency(&nFreq);
    _animationInterval.QuadPart = (LONGLONG)(interval * nFreq.QuadPart);
}

// static member function
Application* Application::getInstance()
{
    CC_ASSERT(sm_pSharedApplication);
    return sm_pSharedApplication;
}

// @deprecated Use getInstance() instead
Application* Application::sharedApplication()
{
    return Application::getInstance();
}

LanguageType Application::getCurrentLanguage()
{
    LanguageType ret = LanguageType::ENGLISH;

    LCID localeID = GetUserDefaultLCID();
    unsigned short primaryLanguageID = localeID & 0xFF;

    switch (primaryLanguageID)
    {
        case LANG_CHINESE:
            ret = LanguageType::CHINESE;
            break;
        case LANG_ENGLISH:
            ret = LanguageType::ENGLISH;
            break;
        case LANG_FRENCH:
            ret = LanguageType::FRENCH;
            break;
        case LANG_ITALIAN:
            ret = LanguageType::ITALIAN;
            break;
        case LANG_GERMAN:
            ret = LanguageType::GERMAN;
            break;
        case LANG_SPANISH:
            ret = LanguageType::SPANISH;
            break;
        case LANG_RUSSIAN:
            ret = LanguageType::RUSSIAN;
            break;
        case LANG_KOREAN:
            ret = LanguageType::KOREAN;
            break;
        case LANG_JAPANESE:
            ret = LanguageType::JAPANESE;
            break;
        case LANG_HUNGARIAN:
            ret = LanguageType::HUNGARIAN;
            break;
        case LANG_PORTUGUESE:
            ret = LanguageType::PORTUGUESE;
            break;
        case LANG_ARABIC:
            ret = LanguageType::ARABIC;
            break;
	    case LANG_NORWEGIAN:
            ret = LanguageType::NORWEGIAN;
            break;
 	    case LANG_POLISH:
            ret = LanguageType::POLISH;
            break;
    }

    return ret;
}

Application::Platform Application::getTargetPlatform()
{
    return Platform::OS_WINDOWS;
}

void Application::setResourceRootPath(const std::string& rootResDir)
{
    _resourceRootPath = rootResDir;
    std::replace(_resourceRootPath.begin(), _resourceRootPath.end(), '\\', '/');
    if (_resourceRootPath[_resourceRootPath.length() - 1] != '/')
    {
        _resourceRootPath += '/';
    }
    FileUtils* pFileUtils = FileUtils::getInstance();
    std::vector<std::string> searchPaths = pFileUtils->getSearchPaths();
    searchPaths.insert(searchPaths.begin(), _resourceRootPath);
    pFileUtils->setSearchPaths(searchPaths);
}

const std::string& Application::getResourceRootPath(void)
{
    return _resourceRootPath;
}

void Application::setStartupScriptFilename(const std::string& startupScriptFile)
{
    _startupScriptFilename = startupScriptFile;
    std::replace(_startupScriptFilename.begin(), _startupScriptFilename.end(), '\\', '/');
}

NS_CC_END

// Local function
static void PVRFrameEnableControlWindow(bool bEnable)
{
    HKEY hKey = 0;

    // Open PVRFrame control key, if not exist create it.
    if(ERROR_SUCCESS != RegCreateKeyExW(HKEY_CURRENT_USER,
        L"Software\\Imagination Technologies\\PVRVFRame\\STARTUP\\",
        0,
        0,
        REG_OPTION_NON_VOLATILE,
        KEY_ALL_ACCESS,
        0,
        &hKey,
        NULL))
    {
        return;
    }

    const WCHAR* wszValue = L"hide_gui";
    const WCHAR* wszNewData = (bEnable) ? L"NO" : L"YES";
    WCHAR wszOldData[256] = {0};
    DWORD   dwSize = sizeof(wszOldData);
    LSTATUS status = RegQueryValueExW(hKey, wszValue, 0, NULL, (LPBYTE)wszOldData, &dwSize);
    if (ERROR_FILE_NOT_FOUND == status              // the key not exist
        || (ERROR_SUCCESS == status                 // or the hide_gui value is exist
        && 0 != wcscmp(wszNewData, wszOldData)))    // but new data and old data not equal
    {
        dwSize = sizeof(WCHAR) * (wcslen(wszNewData) + 1);
        RegSetValueEx(hKey, wszValue, 0, REG_SZ, (const BYTE *)wszNewData, dwSize);
    }

    RegCloseKey(hKey);
}


{
    ts.dumpProperty("sticky-position-at-last-layout", constraints.stickyOffsetAtLastLayout());
    ts.dumpProperty("layer-position-at-last-layout", constraints.layerPositionAtLastLayout());

    return ts;
}

/*
 *
 */

#include "config.h"
#include "ScrollingConstraints.h"

#include <wtf/text/TextStream.h>

namespace WebCore {

FloatPoint FixedPositionViewportConstraints::layerPositionForViewportRect(const FloatRect& viewportRect) const
{
    FloatSize offset;

    if (hasAnchorEdge(AnchorEdgeLeft))
        offset.setWidth(viewportRect.x() - m_viewportRectAtLastLayout.x());
    else if (hasAnchorEdge(AnchorEdgeRight))
        offset.setWidth(viewportRect.maxX() - m_viewportRectAtLastLayout.maxX());

    if (hasAnchorEdge(AnchorEdgeTop))
        offset.setHeight(viewportRect.y() - m_viewportRectAtLastLayout.y());
    else if (hasAnchorEdge(AnchorEdgeBottom))
        offset.setHeight(viewportRect.maxY() - m_viewportRectAtLastLayout.maxY());

    return m_layerPositionAtLastLayout + offset;
}

FloatSize StickyPositionViewportConstraints::computeStickyOffset(const FloatRect& constrainingRect) const
{
    FloatRect boxRect = m_stickyBoxRect;

    if (hasAnchorEdge(AnchorEdgeRight)) {
        float rightLimit = constrainingRect.maxX() - m_rightOffset;
        float rightDelta = std::min<float>(0, rightLimit - m_stickyBoxRect.maxX());
        float availableSpace = std::min<float>(0, m_containingBlockRect.x() - m_stickyBoxRect.x());
        if (rightDelta < availableSpace)
            rightDelta = availableSpace;

        boxRect.move(rightDelta, 0);
    }

    if (hasAnchorEdge(AnchorEdgeLeft)) {
        float leftLimit = constrainingRect.x() + m_leftOffset;
        float leftDelta = std::max<float>(0, leftLimit - m_stickyBoxRect.x());
        float availableSpace = std::max<float>(0, m_containingBlockRect.maxX() - m_stickyBoxRect.maxX());
        if (leftDelta > availableSpace)
            leftDelta = availableSpace;

        boxRect.move(leftDelta, 0);
    }

    if (hasAnchorEdge(AnchorEdgeBottom)) {
        float bottomLimit = constrainingRect.maxY() - m_bottomOffset;
        float bottomDelta = std::min<float>(0, bottomLimit - m_stickyBoxRect.maxY());
        float availableSpace = std::min<float>(0, m_containingBlockRect.y() - m_stickyBoxRect.y());
        if (bottomDelta < availableSpace)
            bottomDelta = availableSpace;

        boxRect.move(0, bottomDelta);
    }

    if (hasAnchorEdge(AnchorEdgeTop)) {
        float topLimit = constrainingRect.y() + m_topOffset;
        float topDelta = std::max<float>(0, topLimit - m_stickyBoxRect.y());
        float availableSpace = std::max<float>(0, m_containingBlockRect.maxY() - m_stickyBoxRect.maxY());
        if (topDelta > availableSpace)
            topDelta = availableSpace;

        boxRect.move(0, topDelta);
    }

    return boxRect.location() - m_stickyBoxRect.location();
}

FloatPoint StickyPositionViewportConstraints::layerPositionForConstrainingRect(const FloatRect& constrainingRect) const
{
    FloatSize offset = computeStickyOffset(constrainingRect);
    return m_layerPositionAtLastLayout + offset - m_stickyOffsetAtLastLayout;
}

TextStream& operator<<(TextStream& ts, const FixedPositionViewportConstraints& constraints)
{
    ts.dumpProperty("viewport-rect-at-last-layout", constraints.viewportRectAtLastLayout());
    ts.dumpProperty("layer-position-at-last-layout", constraints.layerPositionAtLastLayout());

    return ts;
}

TextStream& operator<<(TextStream& ts, const StickyPositionViewportConstraints& constraints)


{
  try {
    const auto &latticeDomain = dynamic_cast<const LatticeDomain &>(domain);

    functionDerivLattice(latticeDomain, jacobian);
  } catch (const std::bad_cast &) {
    throw std::invalid_argument("ILatticeFunction expects domain of type LatticeDomain.");
  } catch (const Kernel::Exception::NotImplementedError &) {
    calNumericalDeriv(domain, jacobian);
  }
}

#include "MantidAPI/ILatticeFunction.h"

namespace Mantid::API {

using namespace Geometry;

ILatticeFunction::ILatticeFunction() : FunctionParameterDecorator() {}

/**
 * Implementation of IFunction::function
 *
 * The implementation tries to cast the supplied domain to LatticeDomain,
 * and calls functionLattice, which needs to be implemented in subclasses.
 *
 * @param domain :: A FunctionDomain of type LatticeDomain
 * @param values :: Function values.
 */
void ILatticeFunction::function(const FunctionDomain &domain, FunctionValues &values) const {
  try {
    const auto &latticeDomain = dynamic_cast<const LatticeDomain &>(domain);

    functionLattice(latticeDomain, values);
  } catch (const std::bad_cast &) {
    throw std::invalid_argument("ILatticeFunction expects domain of type LatticeDomain.");
  }
}

/**
 * Implementation of IFunction::functionDeriv
 *
 * Just like the function-method, the domain is checked for correct type. If
 * functionDerivLattice has not been implemented, numerical derivatives are
 * calculated.
 *
 * @param domain :: A FunctionDomain of type LatticeDomain
 * @param jacobian :: Jacobian matrix
 */
void ILatticeFunction::functionDeriv(const FunctionDomain &domain, Jacobian &jacobian)

void ILatticeFunction::functionDerivLattice(const LatticeDomain &latticeDomain, Jacobian &jacobian) {
  UNUSED_ARG(latticeDomain);
  UNUSED_ARG(jacobian);

  throw Kernel::Exception::NotImplementedError("FunctionLatticeDeriv is not implemented for this function.");
}

} // namespace Mantid::API


void ILatticeFunction::function(const FunctionDomain &domain, FunctionValues &values) const {
  try {
    const auto &latticeDomain = dynamic_cast<const LatticeDomain &>(domain);

    functionLattice(latticeDomain, values);
  } catch (const std::bad_cast &) {
    throw std::invalid_argument("ILatticeFunction expects domain of type LatticeDomain.");
  }
}

#include "MantidAPI/ILatticeFunction.h"

namespace Mantid::API {

using namespace Geometry;

ILatticeFunction::ILatticeFunction() : FunctionParameterDecorator() {}

/**
 * Implementation of IFunction::function
 *
 * The implementation tries to cast the supplied domain to LatticeDomain,
 * and calls functionLattice, which needs to be implemented in subclasses.
 *
 * @param domain :: A FunctionDomain of type LatticeDomain
 * @param values :: Function values.
 */

/**
 * Implementation of IFunction::functionDeriv
 *
 * Just like the function-method, the domain is checked for correct type. If
 * functionDerivLattice has not been implemented, numerical derivatives are
 * calculated.
 *
 * @param domain :: A FunctionDomain of type LatticeDomain
 * @param jacobian :: Jacobian matrix
 */
void ILatticeFunction::functionDeriv(const FunctionDomain &domain, Jacobian &jacobian) {
  try {
    const auto &latticeDomain = dynamic_cast<const LatticeDomain &>(domain);

    functionDerivLattice(latticeDomain, jacobian);
  } catch (const std::bad_cast &) {
    throw std::invalid_argument("ILatticeFunction expects domain of type LatticeDomain.");
  } catch (const Kernel::Exception::NotImplementedError &) {
    calNumericalDeriv(domain, jacobian);
  }
}

void ILatticeFunction::functionDerivLattice(const LatticeDomain &latticeDomain, Jacobian &jacobian) {
  UNUSED_ARG(latticeDomain);
  UNUSED_ARG(jacobian);

  throw Kernel::Exception::NotImplementedError("FunctionLatticeDeriv is not implemented for this function.");
}

} // namespace Mantid::API


try {
    const auto &latticeDomain = dynamic_cast<const LatticeDomain &>(domain);

    functionDerivLattice(latticeDomain, jacobian);
  } catch (const std::bad_cast &) {
    throw std::invalid_argument("ILatticeFunction expects domain of type LatticeDomain.");
  } catch (const Kernel::Exception::NotImplementedError &) {
    calNumericalDeriv(domain, jacobian);
  }

#include "MantidAPI/ILatticeFunction.h"

namespace Mantid::API {

using namespace Geometry;

ILatticeFunction::ILatticeFunction() : FunctionParameterDecorator() {}

/**
 * Implementation of IFunction::function
 *
 * The implementation tries to cast the supplied domain to LatticeDomain,
 * and calls functionLattice, which needs to be implemented in subclasses.
 *
 * @param domain :: A FunctionDomain of type LatticeDomain
 * @param values :: Function values.
 */
void ILatticeFunction::function(const FunctionDomain &domain, FunctionValues &values) const {
  try {
    const auto &latticeDomain = dynamic_cast<const LatticeDomain &>(domain);

    functionLattice(latticeDomain, values);
  } catch (const std::bad_cast &) {
    throw std::invalid_argument("ILatticeFunction expects domain of type LatticeDomain.");
  }
}

/**
 * Implementation of IFunction::functionDeriv
 *
 * Just like the function-method, the domain is checked for correct type. If
 * functionDerivLattice has not been implemented, numerical derivatives are
 * calculated.
 *
 * @param domain :: A FunctionDomain of type LatticeDomain
 * @param jacobian :: Jacobian matrix
 */
void ILatticeFunction::functionDeriv(const FunctionDomain &domain, Jacobian &jacobian) {

}

void ILatticeFunction::functionDerivLattice(const LatticeDomain &latticeDomain, Jacobian &jacobian) {
  UNUSED_ARG(latticeDomain);
  UNUSED_ARG(jacobian);

  throw Kernel::Exception::NotImplementedError("FunctionLatticeDeriv is not implemented for this function.");
}

} // namespace Mantid::API


{
  return VideoStitch::Plugin::DeckLinkDiscovery::create();
}

#include "decklink_reader.hpp"
#include "decklink_writer.hpp"
#include "decklink_discovery.hpp"
#include "export.hpp"

#include "libgpudiscovery/delayLoad.hpp"

#ifdef DELAY_LOAD_ENABLED
SET_DELAY_LOAD_HOOK
#endif  // DELAY_LOAD_ENABLED

extern "C" VS_PLUGINS_EXPORT VideoStitch::Potential<VideoStitch::Input::Reader>* createReaderFn(
    const VideoStitch::Ptv::Value* config, VideoStitch::Plugin::VSReaderPlugin::Config runtime) {
  VideoStitch::Input::DeckLinkReader* decklinkReader =
      VideoStitch::Input::DeckLinkReader::create(runtime.id, config, runtime.width, runtime.height);
  if (decklinkReader) {
    return new VideoStitch::Potential<VideoStitch::Input::Reader>(decklinkReader);
  }
  return new VideoStitch::Potential<VideoStitch::Input::Reader>(
      VideoStitch::Origin::Input, VideoStitch::ErrType::InvalidConfiguration, "Could not create Decklink reader");
}

extern "C" VS_PLUGINS_EXPORT bool handleReaderFn(const VideoStitch::Ptv::Value* config) {
  return VideoStitch::Input::DeckLinkReader::handles(config);
}

extern "C" VS_PLUGINS_EXPORT VideoStitch::Potential<VideoStitch::Output::Output>* createWriterFn(
    const VideoStitch::Ptv::Value* config, VideoStitch::Plugin::VSWriterPlugin::Config runtime) {
  VideoStitch::Output::Output* decklinkWriter = VideoStitch::Output::DeckLinkWriter::create(
      config, runtime.name, runtime.width, runtime.height, runtime.framerate, runtime.depth, runtime.layout);
  if (decklinkWriter) {
    return new VideoStitch::Potential<VideoStitch::Output::Output>(decklinkWriter);
  }
  return new VideoStitch::Potential<VideoStitch::Output::Output>(
      VideoStitch::Origin::Output, VideoStitch::ErrType::InvalidConfiguration, "Could not create Decklink writer");
}
extern "C" VS_PLUGINS_EXPORT bool handleWriterFn(const VideoStitch::Ptv::Value* config) {
  return VideoStitch::Output::DeckLinkWriter::handles(config);
}

extern "C" VS_PLUGINS_EXPORT VideoStitch::Plugin::VSDiscoveryPlugin* discoverFn()


{

    int n, k; scanf("%d %d", &n, &k);
    int t = 240 - k;
    int count(0);
    while(t >= 5 * (count + 1)){++count; t -= 5 * count;}
    count = (n < count) ? n : count;
    printf("%d\n", count);

    return 0;
}


while(t >= 5 * (count + 1)){++count; t -= 5 * count;}

#include <cstdio>

int main(){

    int n, k; scanf("%d %d", &n, &k);
    int t = 240 - k;
    int count(0);

    count = (n < count) ? n : count;
    printf("%d\n", count);

    return 0;
}


{
		assert( getComponentCount( getNonArrayType( getType() ) ) * getArraySize( getType() ) == getComponentCount( getNonArrayType( rhs.getType() ) ) * getArraySize( rhs.getType() )
			&& getComponentType( getNonArrayType( getType() ) ) == getComponentType( getNonArrayType( rhs.getType() ) )
			&& "Can't assign variables with non matching types" );
		updateContainer( rhs );
		return *this;
	}

/*
*/
#include "ShaderWriter/Value.hpp"

#include <ShaderAST/Expr/ExprAddAssign.hpp>
#include <ShaderAST/Expr/ExprAssign.hpp>
#include <ShaderAST/Expr/ExprDivideAssign.hpp>
#include <ShaderAST/Expr/ExprIdentifier.hpp>
#include <ShaderAST/Expr/ExprLiteral.hpp>
#include <ShaderAST/Expr/ExprMinusAssign.hpp>
#include <ShaderAST/Expr/ExprTimesAssign.hpp>
#include <ShaderAST/Stmt/StmtSimple.hpp>
#include <ShaderAST/Shader.hpp>

namespace sdw
{

	Value::Value( ShaderWriter & writer
		, expr::ExprPtr expr
		, bool enabled )
		: m_expr{ std::move( expr ) }
		, m_writer{ &writer }
		, m_shader{ &sdw::getShader( *m_writer ) }
		, m_container{ m_shader ? m_shader->getContainer() : nullptr }
		, m_enabled{ enabled }
	{
	}

	Value::Value( Value const & rhs )
		: Value{ findWriterMandat( rhs )
			, makeExpr( findWriterMandat( rhs ), rhs )
			, rhs.isEnabled() }
	{
	}

	Value & Value::operator=( Value const & rhs )

	void Value::updateContainer( Value const & value )
	{
		if ( !m_container )
		{
			m_container = findContainer( value );
		}
	}

	stmt::Container * Value::getContainer()const
	{
		if ( m_shader )
		{
			return m_shader->getContainer();
		}

		return nullptr;
	}

	void Value::updateExpr( expr::ExprPtr expr )
	{
		m_expr = std::move( expr );
	}

	void Value::doCopy( Value const & rhs )
	{
		if ( rhs.isEnabled() )
		{
			if ( getContainer() )
			{
				if ( isEnabled() )
				{
					ShaderWriter & writer = findWriterMandat( *this, rhs );
					addStmt( writer
						, sdw::makeSimple( sdw::makeAssign( getType()
							, makeExpr( writer, *this )
							, makeExpr( writer, rhs ) ) ) );
				}
			}
			else
			{
				Value::operator=( rhs );
			}
		}
	}

	void Value::doMove( Value && rhs )
	{
		if ( rhs.isEnabled() )
		{
			if ( getContainer() )
			{
				if ( isEnabled() )
				{
					ShaderWriter & writer = findWriterMandat( *this, rhs );
					addStmt( writer
						, sdw::makeSimple( sdw::makeAssign( getType()
							, makeExpr( writer, *this )
							, std::move( rhs.m_expr ) ) ) );
				}
			}
			else
			{
				Value::operator=( std::move( rhs ) );
			}
		}
	}

	expr::ExprPtr getDummyExpr( ShaderWriter const & writer
		, type::TypePtr type )
	{
		return getShader( writer ).getDummyExpr( type );
	}

	expr::ExprPtr makeExpr( Value const & variable
		, bool force )
	{
		assert( variable.getShader() && "Can't use this overload of makeExpr if the Value doesn't have a Shader" );
		return makeExpr( *variable.getWriter()
			, variable.getExpr()
			, force );
	}

	expr::ExprPtr makeExpr( ShaderWriter const & writer
		, Value const & value
		, bool force )
	{
		if ( value.isEnabled() || force )
		{
			return makeExpr( writer
				, value.getExpr()
				, force );
		}

		return getDummyExpr( writer, value.getType() );
	}

	expr::ExprList makeFnArg( ShaderWriter const & writer
		, Value const & variable )
	{
		expr::ExprList result;
		result.emplace_back( makeExpr( writer
			, variable.getExpr()
			, true ) );
		return result;
	}

}


/*
 *
 */

#include "config.h"
#include "Notation.h"

#include "Document.h"

namespace WebCore {

Notation::Notation(Document* document, const String& name, const String& publicId, const String& systemId)
    : ContainerNode(document)
    , m_name(name)
    , m_publicId(publicId)
    , m_systemId(systemId)
{
}

String Notation::nodeName() const
{
    return m_name;
}

Node::NodeType Notation::nodeType() const

PassRefPtr<Node> Notation::cloneNode(bool /*deep*/)
{
    // Spec says cloning Notation nodes is "implementation dependent". We do not support it.
    return 0;
}

bool Notation::childTypeAllowed(NodeType) const
{
    return false;
}

} // namespace


{
        int num = file.lastIndexOf('/');
        if (num == -1) {
            num = file.lastIndexOf('\\');
            GT_CHECK(num != -1, QString("String %1 not looks like file path").arg(file))
        }
        QString path = file.left(num);
        QString name = file.right(file.length() - num - 1);

        GTUtilsDialog::waitForDialog(os, new GTFileDialogUtils(os, path, name));
        GTWidget::click(os, GTWidget::findWidget(os, "addButton", dialog));
    }

/**
 * UGENE - Integrated Bioinformatics Tools.
 *
 */

#include <base_dialogs/GTFileDialog.h>
#include <primitives/GTWidget.h>

#include <QApplication>

#include "CAP3SupportDialogFiller.h"

namespace U2 {

#define GT_CLASS_NAME "StructuralAlignmentDialogFiller"
#define GT_METHOD_NAME "run"

void CAP3SupportDialogFiller::commonScenario() {
    QWidget *dialog = QApplication::activeModalWidget();
    GT_CHECK(dialog != nullptr, "dialog not found");

    foreach (QString file, input)

    int num = output.lastIndexOf('/');
    if (num == -1) {
        num = output.lastIndexOf('\\');
        GT_CHECK(num != -1, QString("String %1 not looks like file path").arg(output))
    }
    QString outputPath = output.left(num);
    QString outputName = output.right(output.length() - num - 1);
    GTUtilsDialog::waitForDialog(os, new GTFileDialogUtils(os, outputPath, outputName, GTFileDialogUtils::Save));
    GTWidget::click(os, GTWidget::findWidget(os, "specifyOutputPathButton", dialog));

    GTUtilsDialog::clickButtonBox(os, dialog, QDialogButtonBox::Ok);
}

#undef GT_METHOD_NAME
#undef GT_CLASS_NAME

}  // namespace U2


{
    if (condition) {
        cout << "Error " __FILE__ "(" << line << "): " << message
             << "    (failed)" << endl;

        if (0 <= testStatus && testStatus <= 100) {
            ++testStatus;
        }
    }
}

#include <ball_loggerfunctorpayloads.h>

#include <ball_loggermanager.h>
#include <ball_loggermanagerconfiguration.h>

#include <bdlf_bind.h>
#include <bdlf_placeholder.h>

#include <bslim_testutil.h>

#include <bsl_cstdlib.h>     // atoi()
#include <bsl_cstring.h>

#include <bsl_new.h>         // placement 'new' syntax
#include <bsl_iostream.h>

using namespace BloombergLP;
using namespace bsl;

//                             TEST PLAN
//                              Overview
// The component under test is a utility consisting of one pure procedure,
// 'setThresholdLevels'.  That lone method is tested using a table-based
// approach where the following test data is tabulated: valid and invalid
// threshold level values; category names; regular expressions.
// Note that places where test drivers in this family are likely to require
// adjustment are indicated by the tag: "ADJ".

//                     STANDARD BDE ASSERT TEST FUNCTION

namespace {

int testStatus = 0;

void aSsErT(bool condition, const char *message, int line)

}  // close unnamed namespace

//               STANDARD BDE TEST DRIVER MACRO ABBREVIATIONS

#define ASSERT       BSLIM_TESTUTIL_ASSERT
#define ASSERTV      BSLIM_TESTUTIL_ASSERTV

#define LOOP_ASSERT  BSLIM_TESTUTIL_LOOP_ASSERT
#define LOOP0_ASSERT BSLIM_TESTUTIL_LOOP0_ASSERT
#define LOOP1_ASSERT BSLIM_TESTUTIL_LOOP1_ASSERT
#define LOOP2_ASSERT BSLIM_TESTUTIL_LOOP2_ASSERT
#define LOOP3_ASSERT BSLIM_TESTUTIL_LOOP3_ASSERT
#define LOOP4_ASSERT BSLIM_TESTUTIL_LOOP4_ASSERT
#define LOOP5_ASSERT BSLIM_TESTUTIL_LOOP5_ASSERT
#define LOOP6_ASSERT BSLIM_TESTUTIL_LOOP6_ASSERT

#define Q            BSLIM_TESTUTIL_Q   // Quote identifier literally.
#define P            BSLIM_TESTUTIL_P   // Print identifier and value.
#define P_           BSLIM_TESTUTIL_P_  // P(X) without '\n'.
#define T_           BSLIM_TESTUTIL_T_  // Print a tab (w/o newline).
#define L_           BSLIM_TESTUTIL_L_  // current Line number

//                  NEGATIVE-TEST MACRO ABBREVIATIONS

#define ASSERT_SAFE_PASS(EXPR) BSLS_ASSERTTEST_ASSERT_SAFE_PASS(EXPR)
#define ASSERT_SAFE_FAIL(EXPR) BSLS_ASSERTTEST_ASSERT_SAFE_FAIL(EXPR)
#define ASSERT_PASS(EXPR)      BSLS_ASSERTTEST_ASSERT_PASS(EXPR)
#define ASSERT_FAIL(EXPR)      BSLS_ASSERTTEST_ASSERT_FAIL(EXPR)
#define ASSERT_OPT_PASS(EXPR)  BSLS_ASSERTTEST_ASSERT_OPT_PASS(EXPR)
#define ASSERT_OPT_FAIL(EXPR)  BSLS_ASSERTTEST_ASSERT_OPT_FAIL(EXPR)

//                  GLOBAL TYPEDEFS/CONSTANTS FOR TESTING

typedef ball::LoggerFunctorPayloads Util;
typedef ball::Category              Cat;

const char *DEFAULT_CATEGORY_NAME = "";

//                               USAGE EXAMPLE 1

namespace BALL_USAGE_EXAMPLE_1 {

// This section illustrates intended use of this component.
///Example: Basic Usage
// The following code snippets illustrate how to use this component's
// 'loadParentCategoryThresholdValues' method to allow a newly-created "child"
// category to inherit the logging threshold levels from its most proximate
// parent category (if such a category already exists).  Note that the category
// "hierarchy" is by naming convention only, but that the callback makes it
// simple for the *user* to impose hierarchical meaning on names that are, from
// the *logger's* perspective, peers.  In this example, we will choose the dot
// character ('.') as the hierarchy delimiter; to the logger itself, '.' is not
// To keep this example transparent, we will create and inspect several
// categories within 'main' directly; some categories will be "declared" to be
// "parent" categories, and we will set the threshold levels explicitly, while
// other categories will act as "children", which is to say that they will
// obtain their threshold levels through the callback mechanism.  In a more
// realistic example, there would be no explicit distinction between "parent"
// and "child" categories, but rather as categories are dynamically
// administered by the user, newly created categories would pick up the changes
// made to existing parents.  As a practical matter, the beginning of the
// function 'main' constitute the "usage" to *install* the callback; the rest
// of this example merely illustrates the *consequences* of that.
// First, we load the logger manager 'configuration' with the desired "payload"
// and use the trailing 'char' argument 'delimiter', set to the value '.',
// which will be bound into the functor and supplied back to the payload on
// each invocation.
    // myapp.cpp
    int main()
    {
        using namespace bdlf::PlaceHolders;

        ball::LoggerManagerConfiguration configuration;
        char delimiter = '.';
        configuration.setDefaultThresholdLevelsCallback(
            bdlf::BindUtil::bind(
               &ball::LoggerFunctorPayloads::loadParentCategoryThresholdValues,
               _1,
               _2,
               _3,
               _4,
               _5,
               delimiter));
// Then, we initialize the logger manager, using the configuration defined
        ball::LoggerManagerScopedGuard guard(configuration);
// The above code is all that the user needs to do to customize the logger to
// "inherit" thresholds from parents.  The rest of this example illustrates the
// consequences of having installed 'myCallback'.  For convenience in what
// follows, we define a reference, 'manager', to the singleton logger manager.
        ball::LoggerManager& manager = ball::LoggerManager::singleton();
// We now create two "parent" categories named "EQUITY.MARKET" and
// "EQUITY.GRAPHICS", and give them arbitrary but distinct threshold levels.
// We also set the default levels to distinct values in order to be able to
// verify exactly where "child" levels have come from later on.
        manager.setDefaultThresholdLevels(128, 96, 64, 32);

        manager.addCategory("EQUITY.MARKET", 127, 95, 63, 31);
        manager.addCategory("EQUITY.GRAPHICS", 129, 97, 65, 33);
// Note that the call to 'addCategory', which takes the four 'int' threshold
// arguments, does not invoke the callback at all, but rather -- assuming that
// the named category does not yet exist -- sets the thresholds to the
// specified values directly.
// We can use the logger manager interface to verify that the levels have been
// set.  First, we use the 'lookupCategory' method to obtain the two parent
        const ball::Category *p1 = manager.lookupCategory("EQUITY.MARKET");
        const ball::Category *p2 = manager.lookupCategory("EQUITY.GRAPHICS");
// Next, we can use the appropriate 'ball::Category' accessor methods to
// 'ASSERT' the expected results.  Recall that the ordered sequence of levels
        ASSERT(127 == p1->recordLevel());
        ASSERT( 95 == p1->passLevel());
        ASSERT( 63 == p1->triggerLevel());
        ASSERT( 31 == p1->triggerAllLevel());

        ASSERT(129 == p2->recordLevel());
        ASSERT( 97 == p2->passLevel());
        ASSERT( 65 == p2->triggerLevel());
        ASSERT( 33 == p2->triggerAllLevel());
// Now, we will add several "child" categories using the 'setCategory' method
// taking a single argument, the 'char*' category name.  This method uses the
// callback in determining the "default" threshold levels to use.  The six
// statements are numbered for subsequent discussion.
        manager.setCategory("EQUITY.MARKET.NYSE");                       // (1)
        manager.setCategory("EQUITY.MARKET.NASDAQ");                     // (2)
        manager.setCategory("EQUITY.GRAPHICS.MATH.FACTORIAL");           // (3)
        manager.setCategory("EQUITY.GRAPHICS.MATH.ACKERMANN");           // (4)
        manager.setCategory("EQUITY.GRAPHICS.MATH");                     // (5)
        manager.setCategory("EQUITY");                                   // (6)
// Note that all six calls to 'setCategory' will succeed in adding new
// categories to the registry.  Calls (1)-(5) will "find" their parent's names
// and "inherit" the parent's levels.  Call (6), however, will not find a
// parent category, and so will receive the default threshold levels, just as
// if there were no callback installed.
// Note also that, although in this "static" (i.e., unadministered) example
// there is no significance to the order in which the above categories are
// created, in general (e.g., when categories are being dynamically
// administered) the order of creation *does* matter.  If line (5) were
// executed before line (4) then the call on line (4) would find the
// "EQUITY.GRAPHICS.MATH" category as its "parent" and inherit those threshold
// levels.  If, before line (4) executed, the thresholds of
// and "EQUITY.GRAPHICS.MATH.ACKERMANN" would have different threshold levels
// despite their equivalent standing in the category hierarchy.
// Let us now verify some of the 24 threshold levels that have been set by the
// above calls.  We will verify the results of lines (1), (3), and (6) above.
        const ball::Category *c1, *c3, *c6;

        c1 =  manager.lookupCategory("EQUITY.MARKET.NYSE");
        ASSERT(127 == c1->recordLevel());
        ASSERT( 95 == c1->passLevel());
        ASSERT( 63 == c1->triggerLevel());
        ASSERT( 31 == c1->triggerAllLevel());

        c3 =  manager.lookupCategory("EQUITY.GRAPHICS.MATH.FACTORIAL");
        ASSERT(129 == c3->recordLevel());
        ASSERT( 97 == c3->passLevel());
        ASSERT( 65 == c3->triggerLevel());
        ASSERT( 33 == c3->triggerAllLevel());

        c6 =  manager.lookupCategory("EQUITY");
        ASSERT(128 == c6->recordLevel());
        ASSERT( 96 == c6->passLevel());
        ASSERT( 64 == c6->triggerLevel());
        ASSERT( 32 == c6->triggerAllLevel());

        return 0;
    }
}  // close namespace BALL_USAGE_EXAMPLE_1

//                              MAIN PROGRAM

int main(int argc, char *argv[])
{
    int test = argc > 1 ? atoi(argv[1]) : 0;
    int verbose = argc > 2;
    int veryVerbose = argc > 3;
    int veryVeryVerbose = argc > 4;

    cout << "TEST " << __FILE__ << " CASE " << test << endl;;

    switch (test) { case 0:  // Zero is always the leading case.
      case 2: {
        // TESTING USAGE EXAMPLE
        //   The usage example provided in the component header file must
        //   compile, link, and run on all platforms as shown.
        //   Incorporate usage example from header into driver, remove leading
        //   USAGE EXAMPLE

        if (verbose) cout << endl << "Testing Usage Example" << endl
                                  << "=====================" << endl;

        BALL_USAGE_EXAMPLE_1::main();

      } break;
      case 1: {
        //   The method under test relies on the services of the 'ball' logger,
        //   but does not modify the state of the logger.  The concerns are
        //   that, given known "parent" categories already registered in the
        //   logger, that the method can "find" the proximate parent as
        //   determined by the position(s) of a specific delimiter character
        //   and correctly load the parent's four threshold values, or else
        //   load the default values if no parent exists.
        //   We are specifically *not* concerned with bsl::string's abilities
        //   to find a specific character among other characters, and so we can
        //   safely and effectively limit parent and child names to simple,
        //   subtly different sequences without compromising this test.  We do
        //   vary name lengths *slightly* to confirm that we correctly
        //   calculate indices in our own code, and we do use different
        //   Since the "factory" default threshold values cannot be relied on,
        //   we must explicitly set known defaults, which will be needed when
        //   a candidate "child" has no parent.
        //   Initialize the logger manager singleton, explicitly set its
        //   default thresholds, and populate its category registry with
        //   "parent" categories and "known" thresholds from a table.  The
        //   parent names use one of two delimiters, '.' and '/', and have
        //   either one or two non-delimiter characters at each name level.
        //   Construct a table of candidate child category names, delimiters,
        //   and expected thresholds (either from a parent or from the default)
        //   and call 'loadParentCategoryThresholdValues' with names and
        //   delimiters from the table, confirming that the four 'int*'
        //   arguments were correctly assigned to.

        if (verbose)
            cout << endl
                 << "Testing 'loadParentCategoryThresholdValues'" << endl
                 << "===========================================" << endl;

        // Initialize Logger Manager.
        ball::LoggerManagerConfiguration lmConfig;
        ball::LoggerManagerScopedGuard   lmGuard(lmConfig);

        ball::LoggerManager& manager = ball::LoggerManager::singleton();

        manager.setDefaultThresholdLevels(10, 11, 12, 13);

        static const struct {
            const char *d_name;
            int         d_record;
            int         d_pass;
            int         d_trigger;
            int         d_triggerAll;
        } PARENT[] = {
            // parent name                       rec.  pass  trig.  trgAll.
            {  "A",                               20,   21,   22,    23 },
            {  "AA",                              30,   31,   32,    33 },
            {  "A.A",                             40,   41,   42,    43 },
            {  "A/A",                             50,   51,   52,    53 },
            {  "AA.A",                            60,   61,   62,    63 },
            {  "AA/A",                            70,   71,   72,    73 },
            {  "A.AA",                            80,   81,   82,    83 },
            {  "A/AA",                            90,   91,   92,    93 }
        };
        const int NUM_PARENTS = sizeof PARENT / sizeof *PARENT;

        if (verbose) cout << "\nPopulating parent categories." << endl;
        for (int i = 0; i < NUM_PARENTS; ++i) {
            const Cat *p = manager.addCategory(PARENT[i].d_name,
                                               PARENT[i].d_record,
                                               PARENT[i].d_pass,
                                               PARENT[i].d_trigger,
                                               PARENT[i].d_triggerAll);

            if (veryVerbose) {
                const Cat *category = manager.lookupCategory(PARENT[i].d_name);
                cout << "\t[ " << PARENT[i].d_name << '\t'
                     << ", " << category->recordLevel()
                     << ", " << category->passLevel()
                     << ", " << category->triggerLevel()
                     << ", " << category->triggerAllLevel()
                     << " ]" << endl;
            }

            ASSERT(p);
        }

        static const struct {
            int         d_line;
            const char *d_name;
            char        d_delimiter;
            int         d_expRecord;
            int         d_expPass;
            int         d_expTrigger;
            int         d_expTriggerAll;
        } DATA[] = {
            // line  child name             delim.  rec.  pass  trig.  trgAll.
            {   L_,  "Z",                    '.',    10,   11,   12,    13 },
            {   L_,  "Z.A",                  '.',    10,   11,   12,    13 },
            {   L_,  "ZZ.A",                 '.',    10,   11,   12,    13 },
            {   L_,  "Z.AA",                 '.',    10,   11,   12,    13 },
            {   L_,  "Z/A",                  '/',    10,   11,   12,    13 },
            {   L_,  "ZZ/A",                 '/',    10,   11,   12,    13 },
            {   L_,  "Z/AA",                 '/',    10,   11,   12,    13 },

            {   L_,  "A.A.A",                '/',    10,   11,   12,    13 },

            {   L_,  "A.B",                  '.',    20,   21,   22,    23 },
            {   L_,  "A%B",                  '%',    20,   21,   22,    23 },
            {   L_,  "AA.B",                 '.',    30,   31,   32,    33 },
            {   L_,  "A.A/A",                '/',    40,   41,   42,    43 },

            {   L_,  "A/A/B",                '/',    50,   51,   52,    53 },
            {   L_,  "A/A/BB",               '/',    50,   51,   52,    53 },
            {   L_,  "A/A/B/C/D",            '/',    50,   51,   52,    53 },

            {   L_,  "AA.A.B",               '.',    60,   61,   62,    63 },
            {   L_,  "AA.A.BBB",             '.',    60,   61,   62,    63 },
            {   L_,  "AA.A.B.CC.DDD",        '.',    60,   61,   62,    63 },
            {   L_,  "AA.A/X/YY/ZZZ",        '/',    60,   61,   62,    63 },

            {   L_,  "AA/A/BB/CC/DD",        '/',    70,   71,   72,    73 },
            {   L_,  "A.AA.BB.CC.DD",        '.',    80,   81,   82,    83 },
            {   L_,  "A/AA/BB/CC/DD",        '/',    90,   91,   92,    93 },
        };
        const int NUM_DATA = sizeof DATA / sizeof *DATA;

        if (verbose) cout << "\nTesting child categories." << endl;

        int recordLevel, passLevel, triggerLevel, triggerAllLevel;
        for (int ti = 0; ti < NUM_DATA; ++ti) {
            const int   LINE           = DATA[ti].d_line;
            const char *NAME           = DATA[ti].d_name;
            const char  DELIM          = DATA[ti].d_delimiter;
            const int   EXP_RECORD     = DATA[ti].d_expRecord;
            const int   EXP_PASS       = DATA[ti].d_expPass;
            const int   EXP_TRIGGER    = DATA[ti].d_expTrigger;
            const int   EXP_TRIGGERALL = DATA[ti].d_expTriggerAll;

            if (veryVerbose) {
                T_;               P_(NAME);
                T_;               P_(DELIM);
                P_(EXP_RECORD);   P_(EXP_PASS);
                P_(EXP_TRIGGER);  P(EXP_TRIGGERALL);
            }

            Util::loadParentCategoryThresholdValues(&recordLevel,
                                                    &passLevel,
                                                    &triggerLevel,
                                                    &triggerAllLevel,
                                                    NAME,
                                                    DELIM);

            if (veryVeryVerbose) {
                T_;                P_(NAME);
                T_;                P_(DELIM);
                P_(recordLevel);   P_(passLevel);
                P_(triggerLevel);  P(triggerAllLevel);
            }

            ASSERTV(LINE, EXP_RECORD     == recordLevel);
            ASSERTV(LINE, EXP_PASS       == passLevel);
            ASSERTV(LINE, EXP_TRIGGER    == triggerLevel);
            ASSERTV(LINE, EXP_TRIGGERALL == triggerAllLevel);

        }

      } break;
      default: {
        cerr << "WARNING: CASE `" << test << "' NOT FOUND." << endl;
        testStatus = -1;
      }
    }

    if (testStatus > 0) {
        cerr << "Error, non-zero test status = " << testStatus << "." << endl;
    }
    return testStatus;
}


{
	Vector vec;
	int count = sscanf( pValue, " [ %f %f %f ]", &vec[0], &vec[1], &vec[2] );
	if ( count == 3 )
	{
		pAttribute->SetValue( vec );
		return true;
	}

	count = sscanf( pValue, " { %f %f %f }", &vec[0], &vec[1], &vec[2] );
	if ( count == 3 )
	{
		vec /= 255.0f;
		pAttribute->SetValue( vec );
		return true;
	}

	return false;
}

#include "vmtdoc.h"
#include "tier1/keyvalues.h"
#include "tier1/utlbuffer.h"
#include "datamodel/dmelement.h"
#include "vmttool.h"
#include "materialsystem/imaterialsystem.h"
#include "materialsystem/ishader.h"
#include "toolutils/enginetools_int.h"
#include "filesystem.h"

// Standard properties
struct StandardParam_t
{
	const char *m_pParamName;
	ShaderParamType_t m_ParamType;
	const char *m_pDefaultValue;
	const char *m_pWidgetType;
	const char *m_pTextType;
};

// NOTE: All entries in here must have all-lowercase param names!
static StandardParam_t g_pStandardParams[] =
{
	{ "$surfaceprop", SHADER_PARAM_TYPE_STRING, "default", "surfacepropertypicker", "surfacePropertyName" },
	{ "%detailtype", SHADER_PARAM_TYPE_STRING, "", "detailtypepicker", "detailTypeName" },
	{ "%compilesky", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
	{ "%compilehint", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
	{ "%compileskip", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
	{ "%compileorigin", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
	{ "%compileclip", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
	{ "%playerclip", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
	{ "%compilenpcclip", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
	{ "%compilenochop", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
	{ "%compiletrigger", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
	{ "%compilenolight", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
	{ "%compileplayercontrolclip", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
	{ "%compileladder", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
	{ "%compilewet", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
	{ "%compilenodraw", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
	{ "%compileinvisible", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
	{ "%compilenonsolid", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
	{ "%compiledetail", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
	{ "%compilewater", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
	{ "%compileslime", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
	{ NULL, SHADER_PARAM_TYPE_BOOL, NULL, NULL, NULL }
};

// Constructor
CVMTDoc::CVMTDoc( IVMTDocCallback *pCallback ) : m_pCallback( pCallback )
{
	m_hRoot = NULL;
	m_pFileName[0] = 0;
	m_bDirty = false;
	m_pCurrentIShader = NULL;

	KeyValues *pKeyValues = new KeyValues( "Wireframe" );
	m_pScratchMaterial.Init( "VMT Preview", pKeyValues );
	g_pDataModel->InstallNotificationCallback( this );
}

CVMTDoc::~CVMTDoc()
{
	if ( m_hRoot.Get() )
	{
		RemoveAllShaderParams( m_hRoot );
	}
	g_pDataModel->RemoveNotificationCallback( this );
}

// Inherited from INotifyUI
void CVMTDoc::NotifyDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags )
{
	OnDataChanged( pReason, nNotifySource, nNotifyFlags );
}

// Gets the file name
const char *CVMTDoc::GetFileName()
{
	return m_pFileName;
}

void CVMTDoc::SetFileName( const char *pFileName )
{
	Q_strncpy( m_pFileName, pFileName, sizeof( m_pFileName ) );
	Q_FixSlashes( m_pFileName );
	SetDirty( true );
}

// Dirty bits
void CVMTDoc::SetDirty( bool bDirty )
{
	m_bDirty = bDirty;
}

bool CVMTDoc::IsDirty() const
{
	return m_bDirty;
}

// Creates the root element
bool CVMTDoc::CreateRootElement()
{
	Assert( !m_hRoot.Get() );

	DmFileId_t fileid = g_pDataModel->FindOrCreateFileId( GetFileName() );

	// Create the main element
	m_hRoot = g_pDataModel->CreateElement( "DmElement", GetFileName(), fileid );
	if ( m_hRoot == DMELEMENT_HANDLE_INVALID )
		return false;

	g_pDataModel->SetFileRoot( fileid, m_hRoot );

	// Each VMT list needs to have an editortype associated with it so it displays nicely in editors
	m_hRoot->SetValue( "editorType", "vmt" );
	m_hRoot->AddAttribute( "proxies", AT_ELEMENT_ARRAY );
	m_hRoot->AddAttribute( "fallbacks", AT_ELEMENT_ARRAY );

	m_pCallback->RemoveAllToolParameters();

	// Add standard parameters
	for ( int i = 0; g_pStandardParams[i].m_pParamName; ++i )
	{
		AddNewShaderParam( m_hRoot, g_pStandardParams[i].m_pParamName, g_pStandardParams[i].m_ParamType,
			g_pStandardParams[i].m_pDefaultValue );

		if ( g_pStandardParams[i].m_pParamName[0] == '%' )
		{
			m_pCallback->AddToolParameter( g_pStandardParams[i].m_pParamName, g_pStandardParams[i].m_pWidgetType, g_pStandardParams[i].m_pTextType );
		}
		else if ( g_pStandardParams[i].m_pWidgetType || g_pStandardParams[i].m_pTextType )
		{
			m_pCallback->RemoveShaderParameter( g_pStandardParams[i].m_pParamName );
			m_pCallback->AddShaderParameter( g_pStandardParams[i].m_pParamName, g_pStandardParams[i].m_pWidgetType, g_pStandardParams[i].m_pTextType );
		}
	}

	return true;
}

// Creates a new VMT
void CVMTDoc::CreateNew()
{
	Assert( !m_hRoot.Get() );

	// This is not undoable
	CAppDisableUndoScopeGuard guard( "CVMTDoc::CreateNew", NOTIFY_CHANGE_OTHER );

	Q_strncpy( m_pFileName, "untitled", sizeof( m_pFileName ) );

	// Create the main element
	if ( !CreateRootElement() )
		return;

	m_pPreviewMaterial.Init( m_pScratchMaterial );

	SetShader( "wireframe" );
	SetDirty( false );
}

// Copies VMT parameters into the root
void CVMTDoc::CopyParamsFromVMT( CDmElement *pVMT )
{
	// First, set the shader parameters
	SetShader( pVMT->GetValueString( "shader" ) );

	// Now, copy the shader parameters over
	CDmAttribute* pSrc;
	CDmAttribute* pDst;
	for ( pSrc = pVMT->FirstAttribute(); pSrc; pSrc = pSrc->NextAttribute() )
	{
		// Only copy shader parameters
		if ( !IsShaderParam( pSrc ) )
			continue;

		// Adds the attribute if it doesn't exist
		const char *pSrcName = pSrc->GetName();
		if ( !m_hRoot->HasAttribute( pSrcName ) )
		{
			m_hRoot->AddAttribute( pSrcName, pSrc->GetType() );
		}
		pDst = m_hRoot->GetAttribute( pSrcName );
		pDst->AddFlag( FATTRIB_USERDEFINED );

		DmAttributeType_t srcType = pSrc->GetType();
		DmAttributeType_t dstType = pDst->GetType();
		if ( dstType == srcType )
		{
			pDst->SetValue( pSrc );
			continue;
		}

		// Certain type conversions are allowed
		switch( dstType )
		{
		case AT_BOOL:
			if ( srcType == AT_INT )
			{
				pDst->SetValue( pSrc );
			}
			break;

		case AT_INT:
			if ( srcType == AT_BOOL )
			{
				pDst->SetValue( pSrc );
			}
			break;

		case AT_COLOR:
			if ( srcType == AT_VECTOR3 )
			{
				Color c;
				int r, g, b;
				Vector v = pSrc->GetValue<Vector>( );
				v *= 255.0f;
				r = clamp( v[0], 0, 255 );
				g = clamp( v[1], 0, 255 );
				b = clamp( v[2], 0, 255 );
				c.SetColor( r, g, b, 255 );
				pDst->SetValue( c );
			}
			break;
		}
	}

	// Any shader parameter that isn't in the VMT make undefined
	for ( pDst = m_hRoot->FirstAttribute(); pDst; pDst = pDst->NextAttribute() )
	{
		if ( !IsShaderParam( pDst ) )
			continue;

		if ( !pVMT->HasAttribute( pDst->GetName() ) )
		{
			// Special hack for alpha + colors
			if ( !Q_stricmp( pDst->GetName(), "$alpha" ) )
			{
				pDst->SetValue( 1.0f );
			}
			else if ( pDst->GetType() == AT_COLOR )
			{
				Color c( 255, 255, 255, 255 );
				pDst->SetValue( c );
			}
			else
			{
				pDst->SetToDefaultValue();
			}
		}
	}
}

// Hooks the preview to an existing material, if there is one
void CVMTDoc::SetupPreviewMaterial( )
{
	// Extract a material name from the material
	char pLocalName[MAX_PATH];

	// relative paths can be passed in for in-game material picking
	if ( !g_pFileSystem->FullPathToRelativePath( m_pFileName, pLocalName, sizeof(pLocalName) ) )
	{
		Q_strcpy( pLocalName, m_pFileName );
	}

	if ( Q_strnicmp( pLocalName, "materials", 9 ) )
		goto noMaterialConnection;

	char pMaterialName[MAX_PATH];
	Q_StripExtension( pLocalName + 10, pMaterialName, sizeof(pMaterialName) );
	IMaterial *pMaterial = g_pMaterialSystem->FindMaterial( pMaterialName, "Editable material", false );
	if ( !pMaterial || pMaterial->IsErrorMaterial() )
		goto noMaterialConnection;

	m_pPreviewMaterial.Init( pMaterial );
	return;

noMaterialConnection:
	m_pPreviewMaterial.Init( m_pScratchMaterial );
}

// Saves/loads from file
bool CVMTDoc::LoadFromFile( const char *pFileName )
{
	Assert( !m_hRoot.Get() );

	SetDirty( false );

	Q_strncpy( m_pFileName, pFileName, sizeof( m_pFileName ) );
	if ( !m_pFileName[0] )
		return false;

	// This is not undoable
	CAppDisableUndoScopeGuard guard( "CVMTDoc::LoadFromFile", NOTIFY_CHANGE_OTHER );

	// Create the main element
	if ( !CreateRootElement() )
		return false;

	// change the filename of all the elements under the root, so we can unload the imported elements later
	DmFileId_t rootFileId = g_pDataModel->GetFileId( m_pFileName );
	g_pDataModel->SetFileName( rootFileId, "<temp>" );

	// This will allow us to edit in context!
	SetupPreviewMaterial( );

	CDmElement *pIVMT = NULL;
	g_pDataModel->RestoreFromFile( m_pFileName, NULL, "vmt", &pIVMT );
	CDmElement *pVMT = CastElement< CDmElement >( pIVMT );
	if ( !pVMT )
		return false;

	// FIXME: This is necessary so that all shader parameters appear in
	// the same order, with the same type, as what you'd get using File->New.
	// If we added a dependency to the material system into dmserializers,
	// we could avoid this work here (I think!).
	CopyParamsFromVMT( pVMT );

	// unload the imported elements and change the root's filename back
	DmFileId_t vmtFileId = g_pDataModel->GetFileId( m_pFileName );
	g_pDataModel->RemoveFileId( vmtFileId );
	g_pDataModel->SetFileName( rootFileId, m_pFileName );

	SetDirty( false );
	return true;
}

// Prior to saving to disk, extract all shader parameters which == the default
CDmElement* CVMTDoc::ExtractDefaultParameters( )
{
	CDmElement *pMaterial = m_hRoot->Copy( );

	CDmAttribute* pAttribute = pMaterial->FirstAttribute();
	CDmAttribute* pNextAttribute = NULL;
	for ( ; pAttribute; pAttribute = pNextAttribute )
	{
		pNextAttribute = pAttribute->NextAttribute();

		const char *pShaderParam = pAttribute->GetName();

		// Check for standard params
		int i;
		for ( i = 0; g_pStandardParams[i].m_pParamName != NULL; ++i )
		{
			if ( !Q_stricmp( g_pStandardParams[i].m_pParamName, pShaderParam ) )
			{
				char temp[512];
				CUtlBuffer buf( temp, sizeof(temp), CUtlBuffer::TEXT_BUFFER | CUtlBuffer::EXTERNAL_GROWABLE );
				pAttribute->Serialize( buf );

				if ( !Q_stricmp( (char*)buf.Base(), g_pStandardParams[i].m_pDefaultValue ) )
				{
					// Buffers match! Therefore it's still using the default parameter
					pMaterial->RemoveAttributeByPtr( pAttribute );
				}
				break;
			}
		}

		// Standard attribute found, continue
		if ( g_pStandardParams[i].m_pParamName )
			continue;

		// Only remove shader parameters
		if ( !IsShaderParam( pAttribute ) )
			continue;

		// Remove flags whose value is 0
		int nCount = g_pMaterialSystem->ShaderFlagCount();
		for ( i = 0; i < nCount; ++i )
		{
			const char *pFlagName = g_pMaterialSystem->ShaderFlagName( i );
			if ( !Q_stricmp( pShaderParam, pFlagName ) )
				break;
		}

		// It's a flag! Remove the attribute if its value is 0
		if ( i != nCount )
		{
			if ( pAttribute->GetValue<bool>( ) == 0 )
			{
				pMaterial->RemoveAttributeByPtr( pAttribute );
			}
			continue;
		}

		// FIXME: We can't do this.. the defaults in the strings need to be changed to
		// make it so they actually match the true defaults
		continue;

		// Remove parameters which match the default value
		nCount = m_pCurrentIShader->GetNumParams();
		for ( i = 0; i < nCount; ++i )
		{
			// FIXME: Check type matches
			if ( Q_stricmp( pShaderParam, m_pCurrentIShader->GetParamName( i ) ) )
				continue;

			// NOTE: This isn't particularly efficient. Too bad!
			// It's hard to do efficiently owing to all the import conversion
			char temp[512];
			char temp2[512];
			CUtlBuffer buf( temp, sizeof(temp), CUtlBuffer::TEXT_BUFFER | CUtlBuffer::EXTERNAL_GROWABLE );
			CUtlBuffer buf2( temp2, sizeof(temp2), CUtlBuffer::TEXT_BUFFER | CUtlBuffer::EXTERNAL_GROWABLE );
			pAttribute->Serialize( buf );
			SetAttributeValueFromDefault( pMaterial, pAttribute, m_pCurrentIShader->GetParamDefault( i ) );
			pAttribute->Serialize( buf2 );

			if ( ( buf.TellMaxPut() == buf2.TellMaxPut() ) && !memcmp( buf.Base(), buf2.Base(), buf.TellMaxPut() ) )
			{
				// Buffers match! Therefore it's still using the default parameter
				pMaterial->RemoveAttributeByPtr( pAttribute );
			}
			else
			{
				// Restore the actual value
				pAttribute->Unserialize( buf );
			}
			break;
		}
	}

	return pMaterial;
}

// Saves to disk
bool CVMTDoc::SaveToFile( )
{
	if ( m_hRoot.Get() && m_pFileName && m_pFileName[0] )
	{
		CDisableUndoScopeGuard guard;
		CDmElement *pSaveRoot = ExtractDefaultParameters();
		bool bOk = g_pDataModel->SaveToFile( m_pFileName, NULL, "keyvalues", "vmt", pSaveRoot );
		DestroyElement( pSaveRoot, TD_DEEP );
		if ( !bOk )
			return false;
	}

	SetDirty( false );
	return true;
}

// Finds a shader
IShader *CVMTDoc::FindShader( const char *pShaderName )
{
	int nCount = g_pMaterialSystem->ShaderCount();
	IShader **ppShaderList = (IShader**)_alloca( nCount * sizeof(IShader*) );
	g_pMaterialSystem->GetShaders( 0, nCount, ppShaderList );
	for ( int i = 0; i < nCount; ++i )
	{
		if ( !Q_stricmp( pShaderName, ppShaderList[i]->GetName() ) )
			return ppShaderList[i];
	}
	return NULL;
}

// Is this attribute a shader parameter?
bool CVMTDoc::IsShaderParam( CDmAttribute* pAttribute )
{
	const char *pName = pAttribute->GetName();

	// Shader params start with a $ or %
	if ( pName[0] != '$' && pName[0] != '%' )
		return false;

	// Don't remove name, type, or id
	if ( pAttribute->IsFlagSet( FATTRIB_STANDARD ) )
		return false;

	// All shader params have USERDEFINED set
	if ( !pAttribute->IsFlagSet( FATTRIB_USERDEFINED ) )
		return false;

	// Don't remove arrays... those aren't shader parameters
	if ( pAttribute->GetType() == AT_ELEMENT_ARRAY )
		return false;

	// Standard params aren't counted here
	for ( int i = 0; g_pStandardParams[i].m_pParamName; ++i )
	{
		if ( !Q_stricmp( g_pStandardParams[i].m_pParamName, pName ) )
			return false;
	}

	return true;
}

// Remove all shader parameters
void CVMTDoc::RemoveAllShaderParams( CDmElement *pMaterial )
{
	CDmAttribute* pAttribute;
	CDmAttribute* pNextAttribute = NULL;
	for ( pAttribute = pMaterial->FirstAttribute(); pAttribute; pAttribute = pNextAttribute )
	{
		pNextAttribute = pAttribute->NextAttribute();

		// Only remove shader parameters
		if ( !IsShaderParam( pAttribute ) )
			continue;

		m_pCallback->RemoveShaderParameter( pAttribute->GetName() );
		pMaterial->RemoveAttributeByPtr( pAttribute );
	}
}

// Remove all shader parameters that don't exist in the new shader
void CVMTDoc::RemoveUnusedShaderParams( CDmElement *pMaterial, IShader *pShader, IShader *pOldShader )
{
	CDmAttribute* pAttribute = pMaterial->FirstAttribute();
	CDmAttribute* pNextAttribute = NULL;
	for ( ; pAttribute; pAttribute = pNextAttribute )
	{
		pNextAttribute = pAttribute->NextAttribute();

		// Only remove shader parameters
		if ( !IsShaderParam( pAttribute ) )
			continue;

		// Don't remove flags
		int nCount = g_pMaterialSystem->ShaderFlagCount();
		int i;
		for ( i = 0; i < nCount; ++i )
		{
			const char *pFlagName = g_pMaterialSystem->ShaderFlagName( i );
			if ( !Q_stricmp( pAttribute->GetName(), pFlagName ) )
				break;
		}

		if ( i != nCount )
			continue;

		const char *pShaderParam = pAttribute->GetName();

		// Remove parameters we've currently got but which don't exist in the new shader
		nCount = pShader->GetNumParams();
		for ( i = 0; i < nCount; ++i )
		{
			// FIXME: Check type matches
			if ( !Q_stricmp( pShaderParam, pShader->GetParamName( i ) ) )
				break;
		}

		// No match? Remove it!
		if ( i == nCount )
		{
			m_pCallback->RemoveShaderParameter( pAttribute->GetName() );
			pMaterial->RemoveAttributeByPtr( pAttribute );
			continue;
		}

		// Remove parameters from the old shader which match the default value
		// This will make the default values update to the new shader's defaults
		if ( pOldShader )
		{
			nCount = pOldShader->GetNumParams();
			for ( i = 0; i < nCount; ++i )
			{
				// FIXME: Check type matches
				if ( Q_stricmp( pShaderParam, pOldShader->GetParamName( i ) ) )
					continue;

				// NOTE: This isn't particularly efficient. Too bad!
				// It's hard to do efficiently owing to all the import conversion
				char temp1[512];
				char temp2[512];
				CUtlBuffer buf1( temp1, sizeof(temp1), CUtlBuffer::TEXT_BUFFER | CUtlBuffer::EXTERNAL_GROWABLE );
				CUtlBuffer buf2( temp2, sizeof(temp2), CUtlBuffer::TEXT_BUFFER | CUtlBuffer::EXTERNAL_GROWABLE );
				pAttribute->Serialize( buf1 );
				SetAttributeValueFromDefault( pMaterial, pAttribute, pOldShader->GetParamDefault( i ) );
				pAttribute->Serialize( buf2 );

				if ( ( buf1.TellMaxPut() == buf2.TellMaxPut() ) && !memcmp( buf1.Base(), buf2.Base(), buf1.TellMaxPut() ) )
				{
					// Buffers match! Therefore it's still using the default parameter
					m_pCallback->RemoveShaderParameter( pAttribute->GetName() );
					pMaterial->RemoveAttributeByPtr( pAttribute );
				}
				else
				{
					pAttribute->Unserialize( buf1 );
				}
				break;
			}
		}
	}
}

// Add attribute for shader parameter
CDmAttribute* CVMTDoc::AddAttributeForShaderParameter( CDmElement *pMaterial, const char *pParamName, ShaderParamType_t paramType )
{
	CDmAttribute *pAttribute = NULL;
	switch ( paramType )
	{
	case SHADER_PARAM_TYPE_INTEGER:
		pAttribute = pMaterial->AddAttribute( pParamName, AT_INT );
		break;

	case SHADER_PARAM_TYPE_BOOL:
		pAttribute = pMaterial->AddAttribute( pParamName, AT_BOOL );
		break;

 	case SHADER_PARAM_TYPE_FLOAT:
		pAttribute = pMaterial->AddAttribute( pParamName, AT_FLOAT );
		break;

	case SHADER_PARAM_TYPE_STRING:
		pAttribute = pMaterial->AddAttribute( pParamName, AT_STRING );
		break;

	case SHADER_PARAM_TYPE_COLOR:
		pAttribute = pMaterial->AddAttribute( pParamName, AT_COLOR );
		break;

	case SHADER_PARAM_TYPE_VEC2:
		pAttribute = pMaterial->AddAttribute( pParamName, AT_VECTOR2 );
		break;

	case SHADER_PARAM_TYPE_VEC3:
		pAttribute = pMaterial->AddAttribute( pParamName, AT_VECTOR3 );
		break;

	case SHADER_PARAM_TYPE_VEC4:
		pAttribute = pMaterial->AddAttribute( pParamName, AT_VECTOR4 );
		break;

	case SHADER_PARAM_TYPE_FOURCC:
		Assert( 0 );
		break;

	case SHADER_PARAM_TYPE_MATRIX:
		pAttribute = pMaterial->AddAttribute( pParamName, AT_VMATRIX );
		break;

	case SHADER_PARAM_TYPE_TEXTURE:
		pAttribute = pMaterial->AddAttribute( pParamName, AT_STRING );
		m_pCallback->AddShaderParameter( pParamName, "vtfpicker", "vtfName" );
		break;

	case SHADER_PARAM_TYPE_MATERIAL:
		pAttribute = pMaterial->AddAttribute( pParamName, AT_STRING );
		m_pCallback->AddShaderParameter( pParamName, "vmtpicker", "vmtName" );
		break;

	default:
		break;
	}

	if ( pAttribute )
	{
		pAttribute->AddFlag( FATTRIB_USERDEFINED );
	}

	return pAttribute;
}

// A couple methods to set vmatrix param values from strings (OLD METHOD!)
bool CVMTDoc::SetVMatrixParamValue( CDmAttribute *pAttribute, const char *pValue )
{
	// FIXME: Change default strings to match DME?
	// Then we could remove this crap
	VMatrix mat;
	int count = sscanf( pValue, " [ %f %f %f %f  %f %f %f %f  %f %f %f %f  %f %f %f %f ]",
		&mat.m[0][0], &mat.m[0][1], &mat.m[0][2], &mat.m[0][3],
		&mat.m[1][0], &mat.m[1][1], &mat.m[1][2], &mat.m[1][3],
		&mat.m[2][0], &mat.m[2][1], &mat.m[2][2], &mat.m[2][3],
		&mat.m[3][0], &mat.m[3][1], &mat.m[3][2], &mat.m[3][3] );
	if (count == 16)
	{
		pAttribute->SetValue( mat );
		return true;
	}

	Vector2D scale, center;
	float angle;
	Vector2D translation;
	count = sscanf( pValue, " center %f %f scale %f %f rotate %f translate %f %f",
		&center.x, &center.y, &scale.x, &scale.y, &angle, &translation.x, &translation.y );
	if (count != 7)
		return false;

	VMatrix temp;
	MatrixBuildTranslation( mat, -center.x, -center.y, 0.0f );
	MatrixBuildScale( temp, scale.x, scale.y, 1.0f );
	MatrixMultiply( temp, mat, mat );
	MatrixBuildRotateZ( temp, angle );
	MatrixMultiply( temp, mat, mat );
	MatrixBuildTranslation( temp, center.x + translation.x, center.y + translation.y, 0.0f );
	MatrixMultiply( temp, mat, mat );
	pAttribute->SetValue( mat );
	return true;
}

// A couple methods to set vmatrix param values from strings (OLD METHOD!)
bool CVMTDoc::SetVector2DParamValue( CDmAttribute *pAttribute, const char *pValue )
{
	Vector2D vec;
	int count = sscanf( pValue, " [ %f %f ]", &vec[0], &vec[1] );
	if ( count == 2 )
	{
		pAttribute->SetValue( vec );
		return true;
	}

	count = sscanf( pValue, " { %f %f }", &vec[0], &vec[1] );
	if ( count == 2 )
	{
		vec /= 255.0f;
		pAttribute->SetValue( vec );
		return true;
	}

	return false;
}

// A couple methods to set vmatrix param values from strings (OLD METHOD!)
bool CVMTDoc::SetVector3DParamValue( CDmAttribute *pAttribute, const char *pValue )

// A couple methods to set vmatrix param values from strings (OLD METHOD!)
bool CVMTDoc::SetVector4DParamValue( CDmAttribute *pAttribute, const char *pValue )
{
	Vector4D vec;
	int count = sscanf( pValue, " [ %f %f %f %f ]", &vec[0], &vec[1], &vec[2], &vec[3] );
	if ( count == 4 )
	{
		pAttribute->SetValue( vec );
		return true;
	}

	count = sscanf( pValue, " { %f %f %f %f }", &vec[0], &vec[1], &vec[2], &vec[3] );
	if ( count == 4 )
	{
		vec /= 255.0f;
		pAttribute->SetValue( vec );
		return true;
	}

	return false;
}

// A couple methods to set vmatrix param values from strings (OLD METHOD!)
bool CVMTDoc::SetColorParamValue( CDmAttribute *pAttribute, const char *pValue )
{
	Color c;
	int r, g, b;
	Vector vec;
	int count = sscanf( pValue, " [ %f %f %f ]", &vec[0], &vec[1], &vec[2] );
	if ( count == 3 )
	{
		vec *= 255.0f;
		r = clamp( vec[0], 0, 255 );
		g = clamp( vec[1], 0, 255 );
		b = clamp( vec[2], 0, 255 );
		c.SetColor( r, g, b, 255 );
		pAttribute->SetValue( c );
		return true;
	}

	count = sscanf( pValue, " { %d %d %d }", &r, &g, &b );
	if ( count == 3 )
	{
		c.SetColor( r, g, b, 255 );
		pAttribute->SetValue( c );
		return true;
	}

	return false;
}

// Sets an attribute value from the shader param default
void CVMTDoc::SetAttributeValueFromDefault( CDmElement *pMaterial, CDmAttribute *pAttribute, const char *pValue )
{
	// FIXME: Change default strings to match DME?
	// Then we could remove this crap
	switch ( pAttribute->GetType() )
	{
	case AT_VMATRIX:
		if ( SetVMatrixParamValue( pAttribute, pValue ) )
			return;
		break;
	case AT_COLOR:
		if ( SetColorParamValue( pAttribute, pValue ) )
			return;
		break;
	case AT_VECTOR2:
		if ( SetVector2DParamValue( pAttribute, pValue ) )
			return;
		break;
	case AT_VECTOR3:
		if ( SetVector3DParamValue( pAttribute, pValue ) )
			return;
		break;
	case AT_VECTOR4:
		if ( SetVector4DParamValue( pAttribute, pValue ) )
			return;
		break;
	}

	pMaterial->SetValueFromString( pAttribute->GetName(), pValue );
}

// Add a single shader parameter if it doesn't exist
void CVMTDoc::AddNewShaderParam( CDmElement *pMaterial, const char *pParamName, ShaderParamType_t paramType, const char *pValue )
{
	char temp[512];
	Q_strncpy( temp, pParamName, sizeof(temp) );
	Q_strlower( temp );
	pParamName = temp;

	CDmAttribute* pAttribute = NULL;
	for ( pAttribute = pMaterial->FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() )
	{
		// Don't bother testing against name, type, or id
		if ( pAttribute->IsFlagSet( FATTRIB_STANDARD ) )
			continue;

		const char *pAttributeName = pAttribute->GetName();
		if ( !Q_stricmp( pAttributeName, pParamName ) )
			return;
	}

	// No match? Add it!
	pAttribute = AddAttributeForShaderParameter( pMaterial, pParamName, paramType );
	if ( pAttribute )
	{
		SetAttributeValueFromDefault( pMaterial, pAttribute, pValue );
	}
}

// Add all shader parameters that don't currently exist
void CVMTDoc::AddNewShaderParams( CDmElement *pMaterial, IShader *pShader )
{
	// First add all flags
	m_pCallback->RemoveAllFlagParameters();
	int nCount = g_pMaterialSystem->ShaderFlagCount();
 	int i;
	for ( i = 0; i < nCount; ++i )
	{
		const char *pParamName = g_pMaterialSystem->ShaderFlagName( i );
		AddNewShaderParam( pMaterial, pParamName, SHADER_PARAM_TYPE_BOOL, "0" );
		m_pCallback->AddFlagParameter( pParamName );
	}

	// Next add all shader-specific parameters
	nCount = pShader->GetNumParams();
	for ( i = 0; i < nCount; ++i )
	{
		const char *pParamName = pShader->GetParamName( i );

		// Don't add parameters that don't want to be editable
		if ( pShader->GetParamFlags( i ) & SHADER_PARAM_NOT_EDITABLE )
			continue;

		ShaderParamType_t paramType = pShader->GetParamType( i );
		const char *pDefault = pShader->GetParamDefault( i );
		AddNewShaderParam( pMaterial, pParamName, paramType, pDefault );
	}
}

// Sets shader parameters to the default for that shader
void CVMTDoc::SetParamsToDefault()
{
	// This is undoable
	CAppUndoScopeGuard guard( 0, "Set Params to Default", "Set Params to Default" );

	// Next add all shader-specific parameters
	int nCount = m_pCurrentIShader->GetNumParams();
	for ( int i = 0; i < nCount; ++i )
	{
		const char *pParamName = m_pCurrentIShader->GetParamName( i );

		// Don't set parameters that don't want to be editable
		if ( m_pCurrentIShader->GetParamFlags( i ) & SHADER_PARAM_NOT_EDITABLE )
			continue;

		char pAttributeName[512];
		Q_strncpy( pAttributeName, pParamName, sizeof(pAttributeName) );
		Q_strlower( pAttributeName );

		if ( !m_hRoot->HasAttribute( pAttributeName ) )
			continue;

		CDmAttribute *pAttribute = m_hRoot->GetAttribute( pAttributeName );
		const char *pDefault = m_pCurrentIShader->GetParamDefault( i );
		SetAttributeValueFromDefault( m_hRoot, pAttribute, pDefault );
	}
}

// Sets the shader in the material
void CVMTDoc::SetShader( const char *pShaderName )
{
	// No change? don't bother
	if ( !Q_stricmp( m_CurrentShader, pShaderName ) )
		return;

	m_CurrentShader = pShaderName;

	// This is undoable
	CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Set Shader", "Set Shader" );

	char pActualShaderName[512];
	g_pMaterialSystem->GetShaderFallback( pShaderName, pActualShaderName, sizeof(pActualShaderName) );

	m_hRoot->SetValue( "shader", pShaderName );

	// First, find the shader
	IShader *pShader = FindShader( pActualShaderName );

	// Remove all shader parameters that don't exist in the new shader
	// And also remove shader parameters that do match the default value
	RemoveUnusedShaderParams( m_hRoot, pShader, m_pCurrentIShader );

	// Add all shader parameters that don't currently exist
	AddNewShaderParams( m_hRoot, pShader );

	m_pCurrentIShader = pShader;
}

// Gets the preview material
IMaterial *CVMTDoc::GetPreviewMaterial()
{
	return m_pPreviewMaterial;
}

// Updates the preview material
void CVMTDoc::UpdatePreviewMaterial()
{
	if ( !m_hRoot.Get() )
		return;

	// Update all shader parameters
	SetShader( m_hRoot->GetValueString( "shader" ) );

	// Use the file conversion to write to a text format
	char buf[1024];
	CUtlBuffer vmtBuf( buf, sizeof(buf), CUtlBuffer::TEXT_BUFFER | CUtlBuffer::EXTERNAL_GROWABLE );
	g_pDataModel->Serialize( vmtBuf, "vmt", "vmt", m_hRoot );

	// Now use the text format to create a keyvalues
	KeyValues *pVMTKeyValues = new KeyValues( "ShaderName" );
	pVMTKeyValues->LoadFromBuffer( "VMT Preview", vmtBuf, g_pFileSystem, "GAME" );

	// Finally, hook the keyvalues into the material.
	m_pPreviewMaterial->SetShaderAndParams( pVMTKeyValues );
	pVMTKeyValues->deleteThis();
}

// Returns the root object
CDmElement *CVMTDoc::GetRootObject()
{
	return m_hRoot;
}

// Called when data changes
void CVMTDoc::OnDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags )
{
	SetDirty( nNotifyFlags & NOTIFY_SETDIRTYFLAG ? true : false );
	UpdatePreviewMaterial();
	m_pCallback->OnDocChanged( pReason, nNotifySource, nNotifyFlags );
}