void Dx12PSOManager::loadCachedPSOInFolder(const char *directory) {
  std::vector<std::string> paths;
  listFilesInFolder(directory, paths, "pso");

  for (const auto &p : paths) {
    PSOCompileResult result = loadCachedPSO(p.c_str());
    insertInPSOCache(result);
  }
}

#include "platform/windows/graphics/dx12/dx12PSOManager.h"

#include <d3d12.h>
#include <d3dcompiler.h>

#include <filesystem>
#include <iostream>

#include "SirEngine/application.h"
#include "SirEngine/engineConfig.h"
#include "SirEngine/events/shaderCompileEvent.h"
#include "SirEngine/globals.h"
#include "SirEngine/io/binaryFile.h"
#include "SirEngine/io/fileUtils.h"
#include "SirEngine/log.h"
#include "SirEngine/runtimeString.h"
#include "nlohmann/json.hpp"
#include "platform/windows/graphics/dx12/dx12RootSignatureManager.h"
#include "platform/windows/graphics/dx12/dx12ShaderManager.h"

namespace SirEngine::dx12 {

static const std::string PSO_KEY_TYPE = "type";
static const std::string DEFAULT_STRING = "";
static const std::string PSO_KEY_SHADER_NAME = "shaderName";
static const std::string PSO_KEY_VS_SHADER = "VS";
static const std::string PSO_KEY_PS_SHADER = "PS";

void Dx12PSOManager::cleanup() {
  // TODO need to be able to iterate hash map even if not ideal;
  // or I cannot free the pso

}

D3D12_SHADER_BYTECODE getShaderByteCodeFromFullPath(const char *path) {
  if (path == nullptr || strcmp(path, "null") == 0) {
    return {nullptr, 0};
  }
  ID3D10Blob *blob =
      path != nullptr
          ? dx12::SHADER_MANAGER->getShaderFromName(getFileName(path).c_str())
          : nullptr;
  return {blob->GetBufferPointer(), blob->GetBufferSize()};
}

void Dx12PSOManager::loadRawPSOInFolder(const char *directory) {
  std::vector<std::string> paths;
  listFilesInFolder(directory, paths, "json");

  const char *shaderPath = frameConcatenation(
      globals::ENGINE_CONFIG->m_dataSourcePath, "/shaders/DX12");
  for (const auto &p : paths) {
    PSOCompileResult result = compileRawPSO(p.c_str(), shaderPath);
    if (result.psoType == PSO_TYPE::INVALID) {
      SE_CORE_ERROR("Could not compile PSO: {0}", p);
    }
    insertInPSOCache(result);
  }
}  // namespace SirEngine::dx12

PSOCompileResult Dx12PSOManager::loadCachedPSO(const char *path) const {
  assert(0);
  const auto expPath = std::filesystem::path(path);
  const std::string name = expPath.stem().string();

  std::vector<char> data;
  // TODO change this to read into temp file
  const bool fileOpenRes = readAllBytes(path, data);
  if (!fileOpenRes) {
    assert(0 && "could not find requested pso file to load");
    return {};
  }
  // extract the header and figure out the mapping of the file
  const BinaryFileHeader *h = getHeader(data.data());
  if (!(h->fileType == BinaryFileType::PSO)) {
    SE_CORE_ERROR(
        "Root signature manager: cannot load PS): \n {0} \n file type is {1}",
        path, getBinaryFileTypeName(static_cast<BinaryFileType>(h->fileType)));
    assert(0);
    return {};
  }
  const auto mapper = getMapperData<PSOMappedData>(data.data());
  char *ptr = data.data() + sizeof(BinaryFileHeader);
  ID3DBlob *blob;
  const HRESULT hr = D3DCreateBlob(mapper->psoSizeInByte, &blob);
  assert(SUCCEEDED(hr) && "failed create blob of data for root signature");
  memcpy(blob->GetBufferPointer(), ptr, blob->GetBufferSize());
  char *ptrOffset = ptr + blob->GetBufferSize();
  ptrOffset += mapper->psoDescSizeInByte;
  // TODO remove PSO name which is not used
  ptrOffset += mapper->psoNameSizeInByte;
  char *vsPath = mapper->vsShaderNameSize == 0 ? nullptr : ptrOffset;
  ptrOffset += mapper->vsShaderNameSize;
  char *psPath = mapper->psShaderNameSize == 0 ? nullptr : ptrOffset;
  ptrOffset += mapper->psShaderNameSize;
  char *csPath = mapper->csShaderNameSize == 0 ? nullptr : ptrOffset;
  ptrOffset += mapper->csShaderNameSize;
  ptrOffset += mapper->inputLayoutSize;
  char *rootSignature = mapper->rootSignatureSize == 0 ? nullptr : ptrOffset;
  ptrOffset += mapper->rootSignatureSize;

  auto psoEnum = static_cast<PSO_TYPE>(mapper->psoType);

  ID3D12PipelineState *state = nullptr;
  PSOCompileResult result{};

  if (psoEnum == PSO_TYPE::RASTER) {
    auto *desc = reinterpret_cast<D3D12_GRAPHICS_PIPELINE_STATE_DESC *>(
        ptr + blob->GetBufferSize());
    desc->CachedPSO.pCachedBlob = blob->GetBufferPointer();
    desc->CachedPSO.CachedBlobSizeInBytes = blob->GetBufferSize();

    // only thing left is to patch the shader in
    desc->VS = getShaderByteCodeFromFullPath(vsPath);
    desc->PS = getShaderByteCodeFromFullPath(psPath);

    desc->InputLayout = {nullptr, 0};
    ID3D12RootSignature *root =
        dx12::ROOT_SIGNATURE_MANAGER->getRootSignatureFromName(
            getFileName(rootSignature).c_str());
    desc->pRootSignature = root;

    HRESULT psoResult =
        DEVICE->CreateGraphicsPipelineState(desc, IID_PPV_ARGS(&state));
    assert(SUCCEEDED(psoResult));

    result.psoType = PSO_TYPE::RASTER;
    result.CSName = nullptr;
    result.VSName = persistentString(vsPath);
    result.PSName = persistentString(psPath);

  } else {
    auto *desc = reinterpret_cast<D3D12_COMPUTE_PIPELINE_STATE_DESC *>(
        ptr + blob->GetBufferSize());
    desc->CachedPSO.pCachedBlob = blob->GetBufferPointer();
    desc->CachedPSO.CachedBlobSizeInBytes = blob->GetBufferSize();
    // only thing left is to patch the shader in
    desc->CS = getShaderByteCodeFromFullPath(csPath);
    ID3D12RootSignature *root =
        dx12::ROOT_SIGNATURE_MANAGER->getRootSignatureFromName(
            getFileName(rootSignature).c_str());
    desc->pRootSignature = root;
    HRESULT psoResult =
        DEVICE->CreateComputePipelineState(desc, IID_PPV_ARGS(&state));
    assert(SUCCEEDED(psoResult));
    result.psoType = PSO_TYPE::COMPUTE;
    result.CSName = persistentString(csPath);
    result.VSName = nullptr;
    result.PSName = nullptr;
  }

  result.pso = state;
  result.PSOFullPathFile = persistentString(path);
  // ONLY PART OF THE STRUCT IS FILLED, SINCE THE RESULT WILL BE USED ONLY FOR
  // RUNTIME CACHING
  return result;
}

void Dx12PSOManager::updatePSOCache(const char *name,
                                    ID3D12PipelineState *pso) {
  assert(m_psoRegisterHandle.containsKey(name));
  PSOHandle handle;
  m_psoRegisterHandle.get(name, handle);
  uint32_t index = getIndexFromHandle(handle);
  PSOData &data = m_psoPool[index];
  // release old one
  data.pso->Release();
  data.pso = pso;
}

void Dx12PSOManager::insertInPSOCache(const PSOCompileResult &result) {
  switch (result.psoType) {
    case PSO_TYPE::DXR:
      break;
    case PSO_TYPE::RASTER: {
      bool hasShader = m_shaderToPSOFile.containsKey(result.VSName);
      if (!hasShader) {
        m_shaderToPSOFile.insert(result.VSName,
                                 new ResizableVector<const char *>(20));
      }
      ResizableVector<const char *> *list;
      m_shaderToPSOFile.get(result.VSName, list);
      // make sure to internalize the string
      list->pushBack(persistentString(result.PSOFullPathFile));

      hasShader = m_shaderToPSOFile.containsKey(result.PSName);
      if (!hasShader) {
        m_shaderToPSOFile.insert(result.PSName,
                                 new ResizableVector<const char *>(20));
      }
      m_shaderToPSOFile.get(result.PSName, list);
      // make sure to internalize the string
      list->pushBack(persistentString(result.PSOFullPathFile));

      // generating and storing the handle
      uint32_t index;
      PSOData &data = m_psoPool.getFreeMemoryData(index);

      const std::string rootName = getFileName(result.rootSignature);

      data.name = persistentString(result.name);
      data.metadata = result.metadata;
      data.pso = result.pso;
      data.rsHandle = result.rsHandle;
      data.topology = result.topologyType;
      data.root = result.graphicDesc->pRootSignature;
      data.type = PSO_TYPE::RASTER;
      const PSOHandle handle{(MAGIC_NUMBER_COUNTER << 16) | index};
      data.magicNumber = MAGIC_NUMBER_COUNTER;
      const std::string psoName = getFileName(result.PSOFullPathFile);
      m_psoRegisterHandle.insert(psoName.c_str(), handle);
      ++MAGIC_NUMBER_COUNTER;
      break;
    }
    case PSO_TYPE::COMPUTE: {
      // can probably wrap this into a function to make it less verbose
      // generating and storing the handle
      uint32_t index;
      PSOData &data = m_psoPool.getFreeMemoryData(index);

      const std::string rootName = getFileName(result.rootSignature);
      data.name = persistentString(result.name);
      data.pso = result.pso;
      data.metadata = result.metadata;
      data.rsHandle = result.rsHandle;
      data.topology = TOPOLOGY_TYPE::UNDEFINED;
      data.type = PSO_TYPE::COMPUTE;
      data.root = result.computeDesc->pRootSignature;
      const PSOHandle handle{(MAGIC_NUMBER_COUNTER << 16) | index};
      data.magicNumber = MAGIC_NUMBER_COUNTER;
      const std::string psoName = getFileName(result.PSOFullPathFile);
      m_psoRegisterHandle.insert(psoName.c_str(), handle);

      ++MAGIC_NUMBER_COUNTER;

      m_psoRegister.insert(result.CSName, result.pso);

      // need to push the pso to the map
      // first we make sure there is a vector to push to
      const bool hasShader = m_shaderToPSOFile.containsKey(result.CSName);
      if (!hasShader) {
        m_shaderToPSOFile.insert(result.CSName,
                                 new ResizableVector<const char *>(20));
      }
      ResizableVector<const char *> *list;
      m_shaderToPSOFile.get(result.CSName, list);
      // make sure to internalize the string
      list->pushBack(persistentString(result.PSOFullPathFile));
      break;
    }
    case PSO_TYPE::INVALID:
      break;
    default:;
  }
}

void Dx12PSOManager::recompilePSOFromShader(const char *shaderName,
                                            const char *offsetPath) {
  // clearing the log
  compileLog = "";
  ResizableVector<const char *> *psos;
  bool found = m_shaderToPSOFile.get(shaderName, psos);
  if (!found) {
    assert(0);
    return;
  }
  // now we need to extract the data out of the pso to figure out which
  // shaders to recompile
  std::vector<std::string> shadersToRecompile;
  shadersToRecompile.reserve(10);
  int psoCount = psos->size();
  for (int i = 0; i < psoCount; ++i) {
    const char *pso = (*psos)[i];
    nlohmann::json jobj;
    getJsonObj(pso, jobj);
    std::cout << "[Engine]: Loading PSO from: " << pso << std::endl;

    const std::string psoTypeString =
        getValueIfInJson(jobj, PSO_KEY_TYPE, DEFAULT_STRING);
    const PSO_TYPE psoType = convertStringPSOTypeToEnum(psoTypeString.c_str());
    switch (psoType) {
      case (PSO_TYPE::COMPUTE): {
        const std::string computeName =
            getValueIfInJson(jobj, PSO_KEY_SHADER_NAME, DEFAULT_STRING);
        assert(!computeName.empty());
        shadersToRecompile.push_back(computeName);
        break;
      }
      case (PSO_TYPE::RASTER): {
        std::string vs =
            getValueIfInJson(jobj, PSO_KEY_VS_SHADER, DEFAULT_STRING);
        assert(!vs.empty());
        std::string ps =
            getValueIfInJson(jobj, PSO_KEY_PS_SHADER, DEFAULT_STRING);
        assert(!ps.empty());
        auto foundVS =
            std::find(shadersToRecompile.begin(), shadersToRecompile.end(), vs);
        if (foundVS == shadersToRecompile.end()) {
          shadersToRecompile.push_back(vs);
        }
        auto foundPS =
            std::find(shadersToRecompile.begin(), shadersToRecompile.end(), ps);
        if (foundPS == shadersToRecompile.end()) {
          shadersToRecompile.push_back(ps);
        }
        break;
      }
      default: {
        assert(0 && "PSO type not supported");
      }
    }
  }

  // recompile all the shaders involved
  for (auto &shader : shadersToRecompile) {
    bool compileResult = false;
    const char *log = dx12::SHADER_MANAGER->recompileShader(
        shader.c_str(), offsetPath, compileResult);
    if (log != nullptr) {
      compileLog += log;
    }
  }

  // now that all shaders are recompiled we can recompile the pso
  // before doing that we do need to flush to make sure none of the PSO are
  // used
  globals::RENDERING_CONTEXT->flush();

  const char *shaderPath = frameConcatenation(
      globals::ENGINE_CONFIG->m_dataSourcePath, "/shaders/DX12");
  if (offsetPath != nullptr) {
    shaderPath = frameConcatenation(offsetPath, shaderPath);
  }
  for (int i = 0; i < psoCount; ++i) {
    const char *pso = (*psos)[i];
    const PSOCompileResult result = compileRawPSO(pso, shaderPath);
    // need to update the cache
    if (result.pso != nullptr) {
      const std::string psoName = getFileName(result.PSOFullPathFile);
      updatePSOCache(psoName.c_str(), result.pso);
      compileLog += "Compiled PSO: ";
    } else {
      compileLog += "failed to  recompile PSO: ";
    }
    compileLog += pso;
    compileLog += "\n";
  }

  // all the shader have been recompiled, we should be able to
  // recompile the PSO now
  ShaderCompileResultEvent *e =
      new ShaderCompileResultEvent(compileLog.c_str());
  globals::APPLICATION->queueEventForEndOfFrame(e);
}

PSOHandle Dx12PSOManager::getHandleFromName(const char *name) const {
  bool r = m_psoRegisterHandle.containsKey(name);
  if (!r) {
    SE_CORE_ERROR("Could not find PSO {0}", name);
    return {};
  }
  PSOHandle value{};
  m_psoRegisterHandle.get(name, value);
  return value;
}

TOPOLOGY_TYPE Dx12PSOManager::getTopology(const PSOHandle psoHandle) const {
  assertMagicNumber(psoHandle);
  const uint32_t idx = getIndexFromHandle(psoHandle);
  const PSOData &data = m_psoPool.getConstRef(idx);
  return data.topology;
}

}  // namespace SirEngine::dx12


void CEditView::TranslateCommand_grep(
	EFunctionCode&	nCommand,
	bool&			bRedraw,
	LPARAM&			lparam1,
	LPARAM&			lparam2,
	LPARAM&			lparam3,
	LPARAM&			lparam4
)
{
	if( ! CEditApp::getInstance()->m_pcGrepAgent->m_bGrepMode )
		return;

	if( nCommand == F_WCHAR ){
		if( WCODE::IsLineDelimiter((wchar_t)lparam1, GetDllShareData().m_Common.m_sEdit.m_bEnableExtEol)
				&& GetDllShareData().m_Common.m_sSearch.m_bGTJW_RETURN ){
			nCommand = F_TAGJUMP;
			lparam1 = GetKeyState_Control()?1:0;
		}
	}
}

/*!	@file
	@brief CEditViewクラスのgrep関連コマンド処理系関数群

	@author genta
	@date	2005/01/10 作成
*/
/*

	This source code is designed for sakura editor.
	Please contact the copyright holders to use this code for other purpose.
*/
#include "StdAfx.h"
#include "view/CEditView.h"
#include "doc/CEditDoc.h"
#include "_main/CControlTray.h"
#include "charset/charcode.h"
#include "CEditApp.h"
#include "CGrepAgent.h"
#include "apiwrap/StdApi.h"
#include "sakura_rc.h"

/*!
	コマンドコードの変換(grep mode時)
*/


AZ::MallocSchema::MallocSchema(const Descriptor& desc) :
    m_bytesAllocated(0)
{
    if (desc.m_useAZMalloc)
    {
        static const int DEFAULT_ALIGNMENT = sizeof(void*) * 2;  // Default malloc alignment

        m_mallocFn = [](size_t byteSize) { return AZ_OS_MALLOC(byteSize, DEFAULT_ALIGNMENT); };
        m_freeFn = [](void* ptr) { AZ_OS_FREE(ptr); };
    }
    else
    {
        m_mallocFn = &malloc;
        m_freeFn = &free;
    }
}

/*
 * Copyright (c) Contributors to the Open 3D Engine Project.
 *
 *
 */

#include <AzCore/Memory/MallocSchema.h>

#include <AzCore/Memory/OSAllocator.h>
#include <AzCore/std/algorithm.h>

namespace AZ
{
    namespace Internal
    {
        struct Header
        {
            uint32_t offset;
            uint32_t size;
        };
    }
}

// MallocSchema methods

AZ::MallocSchema::~MallocSchema()
{
}

AZ::MallocSchema::pointer_type AZ::MallocSchema::Allocate(size_type byteSize, size_type alignment, int flags, const char* name, const char* fileName, int lineNum, unsigned int suppressStackRecord)
{
    (void)flags;
    (void)name;
    (void)fileName;
    (void)lineNum;
    (void)suppressStackRecord;

    if (!byteSize)
    {
        return nullptr;
    }

    if (alignment == 0)
    {
        alignment = sizeof(void*) * 2;  // Default malloc alignment
    }

    AZ_Assert(byteSize < 0x100000000ull, "Malloc allocator only allocates up to 4GB");

    size_type required = byteSize + sizeof(Internal::Header) + ((alignment > sizeof(double)) ? alignment : 0);  // Malloc will align to a minimum boundary for native objects, so we only pad if aligning to a large value
    void* data = (*m_mallocFn)(required);
    void* result = PointerAlignUp(reinterpret_cast<void*>(reinterpret_cast<size_t>(data) + sizeof(Internal::Header)), alignment);
    Internal::Header* header = PointerAlignDown<Internal::Header>((Internal::Header*)(reinterpret_cast<size_t>(result) - sizeof(Internal::Header)), AZStd::alignment_of<Internal::Header>::value);

    header->offset = static_cast<uint32_t>(reinterpret_cast<size_type>(result) - reinterpret_cast<size_type>(data));
    header->size = static_cast<uint32_t>(byteSize);
    m_bytesAllocated += byteSize;

    return result;
}

void AZ::MallocSchema::DeAllocate(pointer_type ptr, size_type byteSize, size_type alignment)
{
    (void)byteSize;
    (void)alignment;

    if (!ptr)
    {
        return;
    }

    Internal::Header* header = PointerAlignDown(reinterpret_cast<Internal::Header*>(reinterpret_cast<size_t>(ptr) - sizeof(Internal::Header)), AZStd::alignment_of<Internal::Header>::value);
    void* freePtr = reinterpret_cast<void*>(reinterpret_cast<size_t>(ptr) - static_cast<size_t>(header->offset));

    m_bytesAllocated -= header->size;
    (*m_freeFn)(freePtr);
}

AZ::MallocSchema::pointer_type AZ::MallocSchema::ReAllocate(pointer_type ptr, size_type newSize, size_type newAlignment)
{
    void* newPtr = Allocate(newSize, newAlignment, 0);
    size_t oldSize = AllocationSize(ptr);

    memcpy(newPtr, ptr, AZStd::min(oldSize, newSize));
    DeAllocate(ptr, 0, 0);

    return newPtr;
}

AZ::MallocSchema::size_type AZ::MallocSchema::Resize(pointer_type ptr, size_type newSize)
{
    (void)ptr;
    (void)newSize;

    return 0;
}

AZ::MallocSchema::size_type AZ::MallocSchema::AllocationSize(pointer_type ptr)
{
    size_type result = 0;

    if (ptr)
    {
        Internal::Header* header = PointerAlignDown(reinterpret_cast<Internal::Header*>(reinterpret_cast<size_t>(ptr) - sizeof(Internal::Header)), AZStd::alignment_of<Internal::Header>::value);
        result = header->size;
    }

    return result;
}

AZ::MallocSchema::size_type AZ::MallocSchema::NumAllocatedBytes() const
{
    return m_bytesAllocated;
}

AZ::MallocSchema::size_type AZ::MallocSchema::Capacity() const
{
    return 0;
}

AZ::MallocSchema::size_type AZ::MallocSchema::GetMaxAllocationSize() const
{
    return 0xFFFFFFFFull;
}

AZ::MallocSchema::size_type AZ::MallocSchema::GetMaxContiguousAllocationSize() const
{
    return AZ_CORE_MAX_ALLOCATOR_SIZE;
}

AZ::IAllocatorAllocate* AZ::MallocSchema::GetSubAllocator()
{
    return nullptr;
}

void AZ::MallocSchema::GarbageCollect()
{
}


void TaggerOptions::Save(FILE* fs) {
  SequenceOptions::Save(fs);

  bool success;
  success = WriteBool(fs, large_feature_set_);
  CHECK(success);
  success = WriteBool(fs, prune_tags_);
  CHECK(success);

  // TODO: Maybe we should load/save also the list of tags for unknown
}

// All Rights Reserved.
// This file is part of TurboParser 2.3.

#include "TaggerOptions.h"
#include "SerializationUtils.h"
#include <glog/logging.h>

using namespace std;

// TODO: Implement the reader for "text".
DEFINE_string(tagger_file_format, "conll",
              "Format of the input file containing the data. Use ""conll"" for "
              "the format used in CONLL-X, and ""text"" for tokenized"
              "sentences (one per line, with tokens separated "
              "by white-spaces.");
//             "Model type. 1 is a bigram model, 2 is a trigram model.");
DEFINE_bool(tagger_large_feature_set, false,
            "True for using a large feature set. Taggers are usually more "
            "accurate but slower and have a larger memory footprint.");
DEFINE_bool(tagger_prune_tags, true,
            "True for pruning the set of possible tags by using a dictionary.");
DEFINE_string(file_unknown_word_tags, "",
              "Path to the file containing the possible tags to be assigned "
              "to out-of-vocabulary words.");

// Save current option flags to the model file.

// Load current option flags to the model file.
// Note: this will override the user-specified flags.
void TaggerOptions::Load(FILE* fs) {
  SequenceOptions::Load(fs);

  bool success;
  success = ReadBool(fs, &FLAGS_tagger_large_feature_set);
  CHECK(success);
  LOG(INFO) << "Setting --tagger_large_feature_set="
    << FLAGS_tagger_large_feature_set;
  success = ReadBool(fs, &FLAGS_tagger_prune_tags);
  CHECK(success);
  LOG(INFO) << "Setting --tagger_prune_tags=" << FLAGS_tagger_prune_tags;

  // TODO: Maybe we should load/save also the list of tags for unknown

  Initialize();
}

void TaggerOptions::Initialize() {
  SequenceOptions::Initialize();

  file_format_ = FLAGS_tagger_file_format;
  large_feature_set_ = FLAGS_tagger_large_feature_set;
  prune_tags_ = FLAGS_tagger_prune_tags;
  file_unknown_word_tags_ = FLAGS_file_unknown_word_tags;
}


/*
 *
 */

#include "config.h"

#if ENABLE(BLOB) || ENABLE(FILE_SYSTEM)

#include "FileStream.h"

#include "PlatformString.h"

namespace WebCore {

FileStream::FileStream()
    : m_handle(invalidPlatformFileHandle)
    , m_bytesProcessed(0)
    , m_totalBytesToRead(0)
{
}

FileStream::~FileStream()
{
    ASSERT(!isHandleValid(m_handle));
}

// FIXME: To be removed when we switch to using BlobData.

void FileStream::stop()
{
    close();
}

long long FileStream::getSize(const String& path, double expectedModificationTime)
{
    // Check the modification time for the possible file change.
    time_t modificationTime;
    if (!getFileModificationTime(path, modificationTime))
        return -1;
    if (expectedModificationTime) {
        if (static_cast<time_t>(expectedModificationTime) != modificationTime)
            return -1;
    }

    // Now get the file size.
    long long length;
    if (!getFileSize(path, length))
        return -1;

    return length;
}

bool FileStream::openForRead(const String& path, long long offset, long long length)
{
    if (isHandleValid(m_handle))
        return true;

    // Open the file.
    m_handle = openFile(path, OpenForRead);
    if (!isHandleValid(m_handle))
        return false;

    // Jump to the beginning position if the file has been sliced.
    if (offset > 0) {
        if (seekFile(m_handle, offset, SeekFromBeginning) < 0)
            return false;
    }

    m_totalBytesToRead = length;
    m_bytesProcessed = 0;

    return true;
}

bool FileStream::openForWrite(const String&)
{
    // FIXME: to be implemented.
    return false;
}

void FileStream::close()
{
    if (isHandleValid(m_handle)) {
        closeFile(m_handle);
        m_handle = invalidPlatformFileHandle;
    }
}

int FileStream::read(char* buffer, int bufferSize)
{
    if (!isHandleValid(m_handle))
        return -1;

    long long remaining = m_totalBytesToRead - m_bytesProcessed;
    int bytesToRead = (remaining < bufferSize) ? static_cast<int>(remaining) : bufferSize;
    int bytesRead = 0;
    if (bytesToRead > 0)
        bytesRead = readFromFile(m_handle, buffer, bytesToRead);
    if (bytesRead < 0)
        return -1;
    if (bytesRead > 0)
        m_bytesProcessed += bytesRead;

    return bytesRead;
}

int FileStream::write(const KURL&, long long, int)
{
    // FIXME: to be implemented.
    return -1;
}

bool FileStream::truncate(long long)
{
    // FIXME: to be implemented.
    return false;
}

} // namespace WebCore

#endif // ENABLE(BLOB) || ENABLE(FILE_SYSTEM)


ChartEntryVolume::ChartEntryVolume(void)
: ChartEntryPrice()
{
}

ChartEntryVolume::~ChartEntryVolume(void) {
}

void ChartEntryVolume::Reserve(size_type nSize ) {
  ChartEntryPrice::Reserve( nSize );
}

void ChartEntryVolume::Append( boost::posix_time::ptime dt, int volume) {
  ChartEntryPrice::Append( dt, (double) volume );
}

void ChartEntryVolume::Append( const ou::tf::Bar& bar ) {
  Append( bar.DateTime(), bar.Volume() );
}

bool ChartEntryVolume::AddEntryToChart( XYChart *pXY, structChartAttributes *pAttributes ) {
  bool bAdded( false );
  ChartEntryPrice::ClearQueue();
  if ( 0 != ChartEntryPrice::Size() ) {
    DoubleArray daXData = ChartEntryTime::GetDateTimes();
    if ( 0 != daXData.len ) {
      BarLayer *bl = pXY->addBarLayer( this->GetPrices() );

      bl->setXData( daXData );
      pAttributes->dblXMin = daXData[0];
      pAttributes->dblXMax = daXData[ daXData.len - 1 ];

      DataSet *pds = bl->getDataSet(0);
      pds->setDataColor( m_eColour, 0xff000000, 0xff000000 );
      pds->setDataName( GetName().c_str() );

      bAdded = true;
    }
  }
  return bAdded;
}

} // ou namespace


string RetTime(bool dot)
{
	time_t Raw;
	time(&Raw);
	const struct tm *Time = localtime(&Raw);

	char Tmp[24];
	if(dot) {
		strftime(Tmp, sizeof(Tmp), "%k:%M", Time);
	} else {
		strftime(Tmp, sizeof(Tmp), "%k %M", Time);
	}

	return string(Tmp);
}

#include "date.h"
#include "main.h"
#include "language.h"

#include "graphic.h"

#include <ctime>
#include <cstdio>
#include <malloc.h>

#include <string>
using std::string;

/**
 * Get the current date as a C string.
 * @param format Date format.
 * @param buf Output buffer.
 * @param size Size of the output buffer.
 * @return Number of bytes written, excluding the NULL terminator.
 * @return Current date. (Caller must free() this string.)
 */
size_t GetDate(DateFormat format, char *buf, size_t size)
{
	time_t Raw;
	time(&Raw);
	const struct tm *Time = localtime(&Raw);

	switch (format) {
		case FORMAT_YDM:
			return strftime(buf, size, "%Y-%d-%m_%k-%M", Time);
		case FORMAT_YMD:
			return strftime(buf, size, "%Y-%m-%d_%k-%M", Time);
		case FORMAT_DM:
			return strftime(buf, size, "%d/%m", Time); // Ex: 26/12
		case FORMAT_MD:
			return strftime(buf, size, "%m/%d", Time); // Ex: 12/26
		case FORMAT_M_D:
			return strftime(buf, size, "%d.%m.", Time); // Ex: 26.12.
		case FORMAT_MY:
			return strftime(buf, size, "%m  %Y", Time);
		case FORMAT_M:
			return strftime(buf, size, "%m", Time);
		case FORMAT_Y:
			return strftime(buf, size, "%Y", Time);
		default:
			break;
	}

	// Should not get here...
	if (size > 0) {
		*buf = 0;
	}
	return 0;
}

/**
 * Get the current time formatted for the top bar.
 * @return std::string containing the time.
 */

/**
 * The blinking ':'.
 * @param donotblink If true, reset the blink counter.
 * @return std::string containing the time.
 */
string RetTimeDot(bool blink)
{
	// Blink the ':' approximately once per second.
	// (120 is because two top frames are drawn every 1/60th
	static int chartimer = 0;
	if (blink) {
		chartimer++;
		if (chartimer >= 120*2) {
			chartimer = 0;
		}
	} else {
		chartimer = 0;
	}

	char Tmp[2];
	if (chartimer >= 120) {
		snprintf(Tmp, sizeof(Tmp), " ");
	} else {
		snprintf(Tmp, sizeof(Tmp), ":");
	}

	return string(Tmp);
}

/**
 * Draw the date using the specified format and color.
 * @param Xpos X position.
 * @param Ypos Y position.
 * @param format Date format.
 * @param color Text color.
 */
void DrawDateF(float x, float y, float scaleX, float scaleY, u32 color, DateFormat format)
{
	char date_str[24];
	GetDate(format, date_str, sizeof(date_str));
	if (date_str[0] == 0)
		return;
	pp2d_draw_text(x, y, scaleX, scaleY, color, date_str);
}

/**
 * Draw the date using the specified color.
 * Date format depends on language setting.
 * @param Xpos X position.
 * @param Ypos Y position.
 * @param color Text color.
 */
void DrawDate(float x, float y, float scaleX, float scaleY, u32 color)
{
	static const uint8_t date_fmt[12] = {
		FORMAT_MD,	// Japanese
		FORMAT_MD,	// English
		FORMAT_DM,	// French
		FORMAT_M_D,	// German
		FORMAT_DM,	// Italian
		FORMAT_DM,	// Spanish
		FORMAT_MD,	// Simplified Chinese
		FORMAT_MD,	// Korean
		FORMAT_DM,	// Dutch
		FORMAT_DM,	// Portuguese
		FORMAT_M_D,	// Russian
		FORMAT_MD,	// Traditional Chinese
	};

	DrawDateF(x, y, scaleX, scaleY, color, (DateFormat)date_fmt[language]);
}


void insert_sleep_aspect1()
   {
      for(int i = 0; i < LOOP_INTERACTIONS; i++)
      { // atomic
         strict_lock<application::aspect_map> guard(my_aspect_map_);

         if(!my_aspect_map_.find<my_msg_aspect_test>(guard))
         {
            my_aspect_map_.insert<my_msg_aspect_test>(boost::make_shared<my_msg_aspect_test>("HI"), guard);

            boost::this_thread::sleep(boost::posix_time::milliseconds(i+5));
         }
      }
   }

// For more information, see http://www.boost.org

#define BOOST_APPLICATION_FEATURE_NS_SELECT_BOOST

#include <iostream>
#include <boost/application.hpp>

#define BOOST_TEST_MODULE AspectMap
#include <boost/test/unit_test.hpp>

using namespace boost;

// Test aspects

class my_msg_aspect_test
{
   std::string hi_message_;

public:

   my_msg_aspect_test(const std::string& hi_message)
      : hi_message_ (hi_message)
   {
   }

   const std::string& say_hi() const
   {
      return hi_message_;
   }

   void set(const std::string& hi_message)
   {
      hi_message_ = hi_message;
   }
};

class my_sum_aspect_test
{
   int result_;

public:

   my_sum_aspect_test(int x, int y)
      : result_ (x+y)
   {
   }

   int get() const
   {
      return result_;
   }

   void add(int z)
   {
      result_ += z;
   }
};

// Reduction for my_msg_aspect_test

shared_ptr<my_msg_aspect_test> my_msg_aspect_test_reduction_function(
   shared_ptr<my_msg_aspect_test> lhs, shared_ptr<my_msg_aspect_test> rhs)
{
   shared_ptr<my_msg_aspect_test> temp(boost::make_shared<my_msg_aspect_test>(""));

   temp->set(lhs->say_hi() + " : " + rhs->say_hi());

   return temp;
}

shared_ptr<my_sum_aspect_test> my_sum_aspect_test_reduction_function(
   shared_ptr<my_sum_aspect_test> lhs, shared_ptr<my_sum_aspect_test> rhs)
{
   shared_ptr<my_sum_aspect_test> temp(boost::make_shared<my_sum_aspect_test>(1, 1));

   temp->add(rhs->get());

   return temp;
}

template<int LOOP_INTERACTIONS = 100>
class parallel_test
{
   application::aspect_map my_aspect_map_;
   boost::thread_group group_;

public:
   parallel_test()
   {
      group_.add_thread( new boost::thread(&parallel_test::insert_sleep_removes_aspect1, this) );
      group_.add_thread( new boost::thread(&parallel_test::insert_sleep_removes_aspect2, this) );
      group_.add_thread( new boost::thread(&parallel_test::find_and_access, this) );
      group_.add_thread( new boost::thread(&parallel_test::insert_sleep_aspect1, this) );
      group_.add_thread( new boost::thread(&parallel_test::use_sleep_remove_aspect1, this) );
   }

   void wait()
   {
      // wait for them
      group_.join_all();
      BOOST_CHECK(my_aspect_map_.size() == 0);
   }

   // use it, sleep and the remove aspect.
   void use_sleep_remove_aspect1()
   {
      for(int i = 0; i < LOOP_INTERACTIONS; i++)
      { // atomic
         strict_lock<application::aspect_map> guard(my_aspect_map_);

         shared_ptr<my_msg_aspect_test> res = my_aspect_map_.find<my_msg_aspect_test>(guard);

         if(res)
         {
            BOOST_CHECK(res->say_hi() == "HI");

            boost::this_thread::sleep(boost::posix_time::milliseconds(i*(3+1)));

            my_aspect_map_.erase<my_msg_aspect_test>(guard);
         }
      }
   }

   // loop with insert/sleep/removes an aspect
   void insert_sleep_removes_aspect1()
   {
      for(int i = 0; i < LOOP_INTERACTIONS; i++)
      { // atomic
         strict_lock<application::aspect_map> guard(my_aspect_map_);

         my_aspect_map_.insert<my_msg_aspect_test>(boost::make_shared<my_msg_aspect_test>("HI"), guard);

         boost::this_thread::sleep(boost::posix_time::milliseconds(i+10));

         my_aspect_map_.erase<my_msg_aspect_test>(guard);
      }
   }

   void insert_sleep_removes_aspect2()
   {
      for(int i = 0; i < LOOP_INTERACTIONS; i++)
      { // atomic
         strict_lock<application::aspect_map> guard(my_aspect_map_);

         my_aspect_map_.insert<my_sum_aspect_test>(boost::make_shared<my_sum_aspect_test>(1,1), guard);

         boost::this_thread::sleep(boost::posix_time::milliseconds(i+15));

         my_aspect_map_.erase<my_sum_aspect_test>(guard);
      }
   }

   // loop with insert and sleep

   // loop to find the aspect and if found do something
   void find_and_access()
   {
      for(int i = 0; i < LOOP_INTERACTIONS; i++)
      { // atomic
         strict_lock<application::aspect_map> guard(my_aspect_map_);

         shared_ptr<my_msg_aspect_test> a1 = my_aspect_map_.find<my_msg_aspect_test>(guard);

         if(a1)
         {
            typedef boost::function2<
               shared_ptr<my_msg_aspect_test> ,
               shared_ptr<my_msg_aspect_test> ,
               shared_ptr<my_msg_aspect_test> > reduction;

            reduction rf =  &my_msg_aspect_test_reduction_function;

            my_aspect_map_.reduce<my_msg_aspect_test, reduction>(make_shared<my_msg_aspect_test>("HI"), rf, guard);
         }

         shared_ptr<my_sum_aspect_test> a2 = my_aspect_map_.find<my_sum_aspect_test>(guard);

         if(a2)
         {
            typedef boost::function2<
               shared_ptr<my_sum_aspect_test> ,
               shared_ptr<my_sum_aspect_test> ,
               shared_ptr<my_sum_aspect_test> > reduction;

            reduction rf =  &my_sum_aspect_test_reduction_function;

            my_aspect_map_.reduce<my_sum_aspect_test, reduction>(make_shared<my_sum_aspect_test>(1,1), rf, guard);
         }
      }
   }
};

// tests

BOOST_AUTO_TEST_CASE(aspect_map)
{
   // Internal locking Version.

   {
      application::aspect_map my_aspect_map;

      BOOST_CHECK(!my_aspect_map.find<my_msg_aspect_test>());
   }

   // insert/find/size
   {
      application::aspect_map my_aspect_map;
      shared_ptr<my_msg_aspect_test> res = my_aspect_map.insert<my_msg_aspect_test>(boost::make_shared<my_msg_aspect_test>("HI"));

      BOOST_CHECK(res.get() == 0);
      BOOST_CHECK(my_aspect_map.size() == 1);
      BOOST_CHECK(my_aspect_map.find<my_msg_aspect_test>()->say_hi() == "HI");
   }

   {
      application::aspect_map my_aspect_map;
      shared_ptr<my_msg_aspect_test> res1 = my_aspect_map.insert<my_msg_aspect_test>(boost::make_shared<my_msg_aspect_test>("HI"));
      shared_ptr<my_msg_aspect_test> res2 = my_aspect_map.insert<my_msg_aspect_test>(boost::make_shared<my_msg_aspect_test>("HI HI"));

      BOOST_CHECK(res2.get()!=0);
      BOOST_CHECK(res2->say_hi() == "HI");
      BOOST_CHECK(my_aspect_map.size()==1);
      BOOST_CHECK(my_aspect_map.find<my_msg_aspect_test>()->say_hi() == "HI");
   }

   // relace
   {
      application::aspect_map my_aspect_map;
      shared_ptr<my_msg_aspect_test> res = my_aspect_map.insert<my_msg_aspect_test>(boost::make_shared<my_msg_aspect_test>("HI"));

      BOOST_CHECK(res.get() == 0);
      BOOST_CHECK(my_aspect_map.size() == 1);
      BOOST_CHECK(my_aspect_map.find<my_msg_aspect_test>()->say_hi() == "HI");

      res = my_aspect_map.exchange<my_msg_aspect_test>(boost::make_shared<my_msg_aspect_test>("HI:HI"));

      BOOST_CHECK(res.get() == 0);
      BOOST_CHECK(my_aspect_map.size() == 1);
      BOOST_CHECK(my_aspect_map.find<my_msg_aspect_test>()->say_hi() == "HI:HI");
   }

   // erase
   {
      application::aspect_map my_aspect_map;
      shared_ptr<my_msg_aspect_test> res = my_aspect_map.insert<my_msg_aspect_test>(boost::make_shared<my_msg_aspect_test>("HI"));

      BOOST_CHECK(res.get() == 0);
      BOOST_CHECK(my_aspect_map.size() == 1);
      BOOST_CHECK(my_aspect_map.find<my_msg_aspect_test>()->say_hi() == "HI");

      res = my_aspect_map.erase<my_msg_aspect_test>();

      BOOST_CHECK(res.get());
      BOOST_CHECK(my_aspect_map.size() == 0);
   }

   // reduction
   {
      typedef boost::function2<
         shared_ptr<my_msg_aspect_test> ,
         shared_ptr<my_msg_aspect_test> ,
         shared_ptr<my_msg_aspect_test> > reduction;

      reduction rf =  &my_msg_aspect_test_reduction_function;

      application::aspect_map my_aspect_map;
      my_aspect_map.insert<my_msg_aspect_test>(make_shared<my_msg_aspect_test>("HI"));
      my_aspect_map.reduce<my_msg_aspect_test, reduction>(make_shared<my_msg_aspect_test>("HI"), rf);

      BOOST_CHECK(my_aspect_map.find<my_msg_aspect_test>()->say_hi() == "HI : HI");
   }

   {
      application::aspect_map my_aspect_map;
      my_aspect_map.insert<my_msg_aspect_test>(boost::make_shared<my_msg_aspect_test>("HI"));

      BOOST_CHECK(my_aspect_map.size());
   }

   // empty
   {
      application::aspect_map my_aspect_map;
      my_aspect_map.insert<my_msg_aspect_test>(boost::make_shared<my_msg_aspect_test>("HI"));

      BOOST_CHECK(my_aspect_map.empty());
   }

   // clear
   {
      application::aspect_map my_aspect_map;
      my_aspect_map.insert<my_msg_aspect_test>(boost::make_shared<my_msg_aspect_test>("HI"));

      my_aspect_map.clear();

      BOOST_CHECK(!my_aspect_map.empty());
   }

   // concurrent acces test
   parallel_test<100>().wait();

}


// File: HUD.cpp
// Class definition for the AMD standard HUD interface.

#include "..\\..\\DXUT\\Core\\DXUT.h"
#include "..\\..\\DXUT\\Core\\DXUTmisc.h"
#include "..\\..\\DXUT\\Optional\\DXUTgui.h"
#include "..\\..\\DXUT\\Optional\\SDKmisc.h"
#include "..\\..\\DXUT\\Core\\DDSTextureLoader.h"
#include "Sprite.h"
#include "HUD.h"

using namespace AMD;

// Constructor

// Destructor
HUD::~HUD()
{
    SAFE_RELEASE( m_pLogoSRV );
}

// Device creation hook function, that loads the AMD logo texture, and creates a sprite
// object
HRESULT HUD::OnCreateDevice( ID3D11Device* pd3dDevice )
{
    HRESULT hr;
    wchar_t str[MAX_PATH];

    m_Sprite.OnCreateDevice( pd3dDevice );

    V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"..\\..\\AMD_SDK\\media\\AMD.dds" ) );
    DirectX::CreateDDSTextureFromFile( pd3dDevice, str, nullptr, &m_pLogoSRV );
    DXUT_SetDebugName( m_pLogoSRV, "AMD.dds" );

    return hr;
}

// Device destruction hook function, that releases the sprite object and
void HUD::OnDestroyDevice()
{
    m_Sprite.OnDestroyDevice();

    SAFE_RELEASE( m_pLogoSRV );
}

// Resize swap chain hook function, that passes through to the sprite object
void HUD::OnResizedSwapChain( const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc )
{
    m_Sprite.OnResizedSwapChain( pBackBufferSurfaceDesc );
}

// Render hook function, that calls the CDXUTDialog::OnRender method, and additionally
// renders the AMD sprite
void HUD::OnRender( float fElapsedTime )
{
    m_GUI.OnRender( fElapsedTime );
    m_Sprite.RenderSprite( m_pLogoSRV, DXUTGetDXGIBackBufferSurfaceDesc()->Width - 250, DXUTGetDXGIBackBufferSurfaceDesc()->Height, 250, 70, true, false );
}

Slider::Slider( CDXUTDialog& dialog, int id, int& y, const wchar_t* label, int min, int max, int& value ) :
m_Value( value ),
m_szLabel( label ),
m_ValueFloat( (float &)value )
{
    dialog.AddStatic( id + 1000000, L"", AMD::HUD::iElementOffset, y += AMD::HUD::iElementDelta, AMD::HUD::iElementWidth, AMD::HUD::iElementHeight, false, &m_pLabel );
    dialog.AddSlider( id, AMD::HUD::iElementOffset, y += AMD::HUD::iElementDelta, AMD::HUD::iElementWidth, AMD::HUD::iElementHeight, min, max, m_Value, false, &m_pSlider );

    dialog.AddControl( this );

    m_Min = min;
    m_Max = max;

    m_UseFloat = false;
    OnGuiEvent();
}

Slider::Slider( CDXUTDialog& dialog, int id, int& y, const wchar_t* label, float min, float max, float step, float& value ) :
m_ValueFloat( value ),
m_MinFloat( min ),
m_MaxFloat( max ),
m_szLabel( label ),
m_Value( (int &)value )
{
    m_Min = 0;
    m_Max = (int)((m_MaxFloat - m_MinFloat) / step + 0.499f);

    int slider_value = (int)((m_ValueFloat - m_MinFloat) / (m_MaxFloat - m_MinFloat) * m_Max + 0.499f);
    dialog.AddStatic( id + 1000000, L"", AMD::HUD::iElementOffset, y += AMD::HUD::iElementDelta, AMD::HUD::iElementWidth, AMD::HUD::iElementHeight, false, &m_pLabel );
    dialog.AddSlider( id, AMD::HUD::iElementOffset, y += AMD::HUD::iElementDelta, AMD::HUD::iElementWidth, AMD::HUD::iElementHeight, m_Min, m_Max, slider_value, false, &m_pSlider );

    dialog.AddControl( this );

    m_UseFloat = true;
    OnGuiEvent();
}

void Slider::OnGuiEvent()
{
    if (m_UseFloat)
    {
        m_ValueFloat = (m_MaxFloat - m_MinFloat) * ((float)m_pSlider->GetValue() / m_Max) + m_MinFloat;
    }
    else
    {
        m_Value = m_pSlider->GetValue();
    }

    wchar_t buff[1024];
    if (m_UseFloat)
    {
        swprintf_s( buff, 1024, L"%s: %f", m_szLabel, m_ValueFloat );
    }
    else
    {
        swprintf_s( buff, 1024, L"%s: %d", m_szLabel, m_Value );
    }

    m_pLabel->SetText( buff );
}

void Slider::SetEnabled( bool enable )
{
    m_pLabel->SetEnabled( enable );
    m_pSlider->SetEnabled( enable );
}

void Slider::SetVisible( bool visible )
{
    m_pLabel->SetVisible( visible );
    m_pSlider->SetVisible( visible );
}

void Slider::SetValue( int value )
{
    if (m_UseFloat == true) { return; }
    m_pSlider->SetValue( value );
    OnGuiEvent();
}

void Slider::SetValue( float value )
{
    if (m_UseFloat != true) { return; }

    int slider_value = (int)((value - m_MinFloat) / (m_MaxFloat - m_MinFloat) * m_Max + 0.499f);

    m_pSlider->SetValue( (int)slider_value );
    OnGuiEvent();
}


void ClearAll(int n) {
    for(int i = 0; i < n; i++) G[i].clear();
    edges.clear();
  }

// UVa10779 Collector's Problem
// Rujia Liu
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;

const int maxn = 100 + 10;
const int INF = 1000000000;

struct Edge {
  int from, to, cap, flow;
};

bool operator < (const Edge& a, const Edge& b) {
  return a.from < b.from || (a.from == b.from && a.to < b.to);
}

struct Dinic {
  int n, m, s, t;
  vector<Edge> edges;    // 边数的两倍
  vector<int> G[maxn];   // 邻接表，G[i][j]表示结点i的第j条边在e数组中的序号
  bool vis[maxn];        // BFS使用
  int d[maxn];           // 从起点到i的距离
  int cur[maxn];         // 当前弧指针

  void ClearFlow() {
    for(int i = 0; i < edges.size(); i++) edges[i].flow = 0;
  }

  void AddEdge(int from, int to, int cap) {
    edges.push_back((Edge){from, to, cap, 0});
    edges.push_back((Edge){to, from, 0, 0});
    m = edges.size();
    G[from].push_back(m-2);
    G[to].push_back(m-1);
  }

  bool BFS() {
    memset(vis, 0, sizeof(vis));
    queue<int> Q;
    Q.push(s);
    vis[s] = 1;
    d[s] = 0;
    while(!Q.empty()) {
      int x = Q.front(); Q.pop();
      for(int i = 0; i < G[x].size(); i++) {
        Edge& e = edges[G[x][i]];
        if(!vis[e.to] && e.cap > e.flow) {
          vis[e.to] = 1;
          d[e.to] = d[x] + 1;
          Q.push(e.to);
        }
      }
    }
    return vis[t];
  }

  int DFS(int x, int a) {
    if(x == t || a == 0) return a;
    int flow = 0, f;
    for(int& i = cur[x]; i < G[x].size(); i++) {
      Edge& e = edges[G[x][i]];
      if(d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap-e.flow))) > 0) {
        e.flow += f;
        edges[G[x][i]^1].flow -= f;
        flow += f;
        a -= f;
        if(a == 0) break;
      }
    }
    return flow;
  }

  int Maxflow(int s, int t) {
    this->s = s; this->t = t;
    int flow = 0;
    while(BFS()) {
      memset(cur, 0, sizeof(cur));
      flow += DFS(s, INF);
    }
    return flow;
  }
};

Dinic g;

int main() {
  int T, n, m;
  scanf("%d", &T);
  for(int kase = 1; kase <= T; kase++) {
    scanf("%d%d", &n, &m);
    g.ClearAll(n+m+1); // s=0, 物品为结点1~m, 除Bob外的人为结点m+1~m+n-1，t=m+n
    for(int i = 0; i < n; i++) {
      int k, kind;
      scanf("%d", &k);
      vector<int> cnt(m+1, 0);
      for(int j = 0; j < k; j++) { scanf("%d", &kind); cnt[kind]++; }
      if(i == 0) { // Bob
        for(int j = 1; j <= m; j++)
          if(cnt[j] >= 1) g.AddEdge(0, j, cnt[j]); // s连边到物品
      } else { // 其他人
        for(int j = 1; j <= m; j++) {
          if(cnt[j] >= 2) g.AddEdge(m+i, j, cnt[j]-1); // 此人可以给出cnt[j]-1个物品j
          else if(cnt[j] == 0) g.AddEdge(j, m+i, 1); // 此人可以接受1个物品j
        }
      }
    }
    for(int i = 1; i <= m; i++) g.AddEdge(i, m+n, 1);
    printf("Case #%d: %d\n", kase, g.Maxflow(0, m+n));
  }
  return 0;
}


void drawModelNodes(tinygltf::Model &model, tinygltf::Node &node) {
  if ((node.mesh >= 0) && (node.mesh < model.meshes.size())) {
    drawMesh(model, model.meshes[node.mesh]);
  }
  for (size_t i = 0; i < node.children.size(); i++) {
    drawModelNodes(model, model.nodes[node.children[i]]);
  }
}

#include <fstream>
#include <iostream>

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/gtc/matrix_transform.hpp>

#include "shaders.h"
#include "window.h"

#define TINYGLTF_IMPLEMENTATION
#define STB_IMAGE_IMPLEMENTATION
#define STB_IMAGE_WRITE_IMPLEMENTATION
#define TINYGLTF_NOEXCEPTION
#define JSON_NOEXCEPTION
#include "../../tiny_gltf.h"

#define BUFFER_OFFSET(i) ((char *)NULL + (i))

bool loadModel(tinygltf::Model &model, const char *filename) {
  tinygltf::TinyGLTF loader;
  std::string err;
  std::string warn;

  bool res = loader.LoadASCIIFromFile(&model, &err, &warn, filename);
  if (!warn.empty()) {
    std::cout << "WARN: " << warn << std::endl;
  }

  if (!err.empty()) {
    std::cout << "ERR: " << err << std::endl;
  }

  if (!res)
    std::cout << "Failed to load glTF: " << filename << std::endl;
  else
    std::cout << "Loaded glTF: " << filename << std::endl;

  return res;
}

std::map<int, GLuint> bindMesh(std::map<int, GLuint> vbos,
                               tinygltf::Model &model, tinygltf::Mesh &mesh) {
  for (size_t i = 0; i < model.bufferViews.size(); ++i) {
    const tinygltf::BufferView &bufferView = model.bufferViews[i];
    if (bufferView.target == 0) {  // TODO impl drawarrays
      std::cout << "WARN: bufferView.target is zero" << std::endl;
      continue;  // Unsupported bufferView.
                 /*
                   From spec2.0 readme:
                   http://example.com
                            ... drawArrays function should be used with a count equal to
                   the count            property of any of the accessors referenced by the
                   attributes            property            (they are all equal for a given
                   primitive).
                 */
    }

    const tinygltf::Buffer &buffer = model.buffers[bufferView.buffer];
    std::cout << "bufferview.target " << bufferView.target << std::endl;

    GLuint vbo;
    glGenBuffers(1, &vbo);
    vbos[i] = vbo;
    glBindBuffer(bufferView.target, vbo);

    std::cout << "buffer.data.size = " << buffer.data.size()
              << ", bufferview.byteOffset = " << bufferView.byteOffset
              << std::endl;

    glBufferData(bufferView.target, bufferView.byteLength,
                 &buffer.data.at(0) + bufferView.byteOffset, GL_STATIC_DRAW);
  }

  for (size_t i = 0; i < mesh.primitives.size(); ++i) {
    tinygltf::Primitive primitive = mesh.primitives[i];
    tinygltf::Accessor indexAccessor = model.accessors[primitive.indices];

    for (auto &attrib : primitive.attributes) {
      tinygltf::Accessor accessor = model.accessors[attrib.second];
      int byteStride =
          accessor.ByteStride(model.bufferViews[accessor.bufferView]);
      glBindBuffer(GL_ARRAY_BUFFER, vbos[accessor.bufferView]);

      int size = 1;
      if (accessor.type != TINYGLTF_TYPE_SCALAR) {
        size = accessor.type;
      }

      int vaa = -1;
      if (attrib.first.compare("POSITION") == 0) vaa = 0;
      if (attrib.first.compare("NORMAL") == 0) vaa = 1;
      if (attrib.first.compare("TEXCOORD_0") == 0) vaa = 2;
      if (vaa > -1) {
        glEnableVertexAttribArray(vaa);
        glVertexAttribPointer(vaa, size, accessor.componentType,
                              accessor.normalized ? GL_TRUE : GL_FALSE,
                              byteStride, BUFFER_OFFSET(accessor.byteOffset));
      } else
        std::cout << "vaa missing: " << attrib.first << std::endl;
    }

    if (model.textures.size() > 0) {
      // fixme: Use material's baseColor
      tinygltf::Texture &tex = model.textures[0];

      if (tex.source > -1) {

        GLuint texid;
        glGenTextures(1, &texid);

        tinygltf::Image &image = model.images[tex.source];

        glBindTexture(GL_TEXTURE_2D, texid);
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

        GLenum format = GL_RGBA;

        if (image.component == 1) {
          format = GL_RED;
        } else if (image.component == 2) {
          format = GL_RG;
        } else if (image.component == 3) {
          format = GL_RGB;
        } else {
        }

        GLenum type = GL_UNSIGNED_BYTE;
        if (image.bits == 8) {
          // ok
        } else if (image.bits == 16) {
          type = GL_UNSIGNED_SHORT;
        } else {
        }

        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0,
                     format, type, &image.image.at(0));
      }
    }
  }

  return vbos;
}

// bind models
void bindModelNodes(std::map<int, GLuint> vbos, tinygltf::Model &model,
                    tinygltf::Node &node) {
  if ((node.mesh >= 0) && (node.mesh < model.meshes.size())) {
    bindMesh(vbos, model, model.meshes[node.mesh]);
  }

  for (size_t i = 0; i < node.children.size(); i++) {
    assert((node.children[i] >= 0) && (node.children[i] < model.nodes.size()));
    bindModelNodes(vbos, model, model.nodes[node.children[i]]);
  }
}
GLuint bindModel(tinygltf::Model &model) {
  std::map<int, GLuint> vbos;
  GLuint vao;
  glGenVertexArrays(1, &vao);
  glBindVertexArray(vao);

  const tinygltf::Scene &scene = model.scenes[model.defaultScene];
  for (size_t i = 0; i < scene.nodes.size(); ++i) {
    assert((scene.nodes[i] >= 0) && (scene.nodes[i] < model.nodes.size()));
    bindModelNodes(vbos, model, model.nodes[scene.nodes[i]]);
  }

  glBindVertexArray(0);
  // cleanup vbos
  for (size_t i = 0; i < vbos.size(); ++i) {
    glDeleteBuffers(1, &vbos[i]);
  }

  return vao;
}

void drawMesh(tinygltf::Model &model, tinygltf::Mesh &mesh) {
  for (size_t i = 0; i < mesh.primitives.size(); ++i) {
    tinygltf::Primitive primitive = mesh.primitives[i];
    tinygltf::Accessor indexAccessor = model.accessors[primitive.indices];

    glDrawElements(primitive.mode, indexAccessor.count,
                   indexAccessor.componentType,
                   BUFFER_OFFSET(indexAccessor.byteOffset));
  }
}

// recursively draw node and children nodes of model

void drawModel(GLuint vao, tinygltf::Model &model) {
  glBindVertexArray(vao);

  const tinygltf::Scene &scene = model.scenes[model.defaultScene];
  for (size_t i = 0; i < scene.nodes.size(); ++i) {
    drawModelNodes(model, model.nodes[scene.nodes[i]]);
  }

  glBindVertexArray(0);
}

void dbgModel(tinygltf::Model &model) {
  for (auto &mesh : model.meshes) {
    std::cout << "mesh : " << mesh.name << std::endl;
    for (auto &primitive : mesh.primitives) {
      const tinygltf::Accessor &indexAccessor =
          model.accessors[primitive.indices];

      std::cout << "indexaccessor: count " << indexAccessor.count << ", type "
                << indexAccessor.componentType << std::endl;

      tinygltf::Material &mat = model.materials[primitive.material];
      for (auto &mats : mat.values) {
        std::cout << "mat : " << mats.first.c_str() << std::endl;
      }

      for (auto &image : model.images) {
        std::cout << "image name : " << image.uri << std::endl;
        std::cout << "  size : " << image.image.size() << std::endl;
        std::cout << "  w/h : " << image.width << "/" << image.height
                  << std::endl;
      }

      std::cout << "indices : " << primitive.indices << std::endl;
      std::cout << "mode     : "
                << "(" << primitive.mode << ")" << std::endl;

      for (auto &attrib : primitive.attributes) {
        std::cout << "attribute : " << attrib.first.c_str() << std::endl;
      }
    }
  }
}

glm::mat4 genView(glm::vec3 pos, glm::vec3 lookat) {
  // Camera matrix
  glm::mat4 view = glm::lookAt(
      pos,                // Camera in World Space
      lookat,             // and looks at the origin
      glm::vec3(0, 1, 0)  // Head is up (set to 0,-1,0 to look upside-down)
  );

  return view;
}

glm::mat4 genMVP(glm::mat4 view_mat, glm::mat4 model_mat, float fov, int w,
                 int h) {
  glm::mat4 Projection =
      glm::perspective(glm::radians(fov), (float)w / (float)h, 0.01f, 1000.0f);

  // Or, for an ortho camera :
  // // In world coordinates

  glm::mat4 mvp = Projection * view_mat * model_mat;

  return mvp;
}

void displayLoop(Window &window, const std::string &filename) {
  Shaders shader = Shaders();
  glUseProgram(shader.pid);

  // grab uniforms to modify
  GLuint MVP_u = glGetUniformLocation(shader.pid, "MVP");
  GLuint sun_position_u = glGetUniformLocation(shader.pid, "sun_position");
  GLuint sun_color_u = glGetUniformLocation(shader.pid, "sun_color");

  tinygltf::Model model;
  if (!loadModel(model, filename.c_str())) return;

  GLuint vao = bindModel(model);

  // Model matrix : an identity matrix (model will be at the origin)
  glm::mat4 model_mat = glm::mat4(1.0f);
  glm::mat4 model_rot = glm::mat4(1.0f);
  glm::vec3 model_pos = glm::vec3(-3, 0, -3);

  // generate a camera view, based on eye-position and lookAt world-position
  glm::mat4 view_mat = genView(glm::vec3(2, 2, 20), model_pos);

  glm::vec3 sun_position = glm::vec3(3.0, 10.0, -5.0);
  glm::vec3 sun_color = glm::vec3(1.0);

  while (!window.Close()) {
    window.Resize();

    glClearColor(0.2, 0.2, 0.2, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glm::mat4 trans =
        glm::translate(glm::mat4(1.0f), model_pos);  // reposition model
    model_rot = glm::rotate(model_rot, glm::radians(0.8f),
                            glm::vec3(0, 1, 0));  // rotate model on y axis
    model_mat = trans * model_rot;

    // build a model-view-projection
    GLint w, h;
    glfwGetWindowSize(window.window, &w, &h);
    glm::mat4 mvp = genMVP(view_mat, model_mat, 45.0f, w, h);
    glUniformMatrix4fv(MVP_u, 1, GL_FALSE, &mvp[0][0]);

    glUniform3fv(sun_position_u, 1, &sun_position[0]);
    glUniform3fv(sun_color_u, 1, &sun_color[0]);

    drawModel(vao, model);
    glfwSwapBuffers(window.window);
    glfwPollEvents();
  }
}

static void error_callback(int error, const char *description) {
  (void)error;
  fprintf(stderr, "Error: %s\n", description);
}

int main(int argc, char **argv) {
  std::string filename = "../../../models/Cube/Cube.gltf";

  if (argc > 1) {
    filename = argv[1];
  }

  glfwSetErrorCallback(error_callback);

  if (!glfwInit()) return -1;

  // Force create OpenGL 3.3
  // NOTE(syoyo): Linux + NVIDIA driver segfaults for some reason? commenting out glfwWindowHint will work.
  // Note (PE): On laptops with intel hd graphics card you can overcome the segfault by enabling experimental, see below (tested on lenovo thinkpad)
  glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
  glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
  glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
  glewExperimental = GL_TRUE;

#ifdef __APPLE__
  glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif

  Window window = Window(800, 600, "TinyGLTF basic example");
  glfwMakeContextCurrent(window.window);

#ifdef __APPLE__
  glewExperimental = GL_TRUE;
#endif

  glewInit();
  std::cout << glGetString(GL_RENDERER) << ", " << glGetString(GL_VERSION)
            << std::endl;

  if (!GLEW_VERSION_3_3) {
    std::cerr << "OpenGL 3.3 is required to execute this app." << std::endl;
    return EXIT_FAILURE;
  }

  glEnable(GL_DEPTH_TEST);
  glDepthFunc(GL_LESS);

  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  glEnable(GL_BLEND);

  displayLoop(window, filename);

  glfwTerminate();
  return 0;
}


try
    {
        return term->resolve (scope, 0)->toDouble();
    }
    catch (Helpers::EvaluationError& e)
    {
        evaluationError = e.description;
    }

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

   This file is part of the juce_core module of the JUCE library.

   ------------------------------------------------------------------------------

   using any other modules, be sure to check that you also comply with their license.

   For more details, visit www.juce.com

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

class Expression::Term  : public SingleThreadedReferenceCountedObject
{
public:
    Term() {}
    virtual ~Term() {}

    virtual Type getType() const noexcept = 0;
    virtual Term* clone() const = 0;
    virtual ReferenceCountedObjectPtr<Term> resolve (const Scope&, int recursionDepth) = 0;
    virtual String toString() const = 0;
    virtual double toDouble() const                                          { return 0; }
    virtual int getInputIndexFor (const Term*) const                         { return -1; }
    virtual int getOperatorPrecedence() const                                { return 0; }
    virtual int getNumInputs() const                                         { return 0; }
    virtual Term* getInput (int) const                                       { return nullptr; }
    virtual ReferenceCountedObjectPtr<Term> negated();

    virtual ReferenceCountedObjectPtr<Term> createTermToEvaluateInput (const Scope&, const Term* /*inputTerm*/,
                                                                       double /*overallTarget*/, Term* /*topLevelTerm*/) const
    {
        jassertfalse;
        return ReferenceCountedObjectPtr<Term>();
    }

    virtual String getName() const
    {
        jassertfalse; // You shouldn't call this for an expression that's not actually a function!
        return String();
    }

    virtual void renameSymbol (const Symbol& oldSymbol, const String& newName, const Scope& scope, int recursionDepth)
    {
        for (int i = getNumInputs(); --i >= 0;)
            getInput (i)->renameSymbol (oldSymbol, newName, scope, recursionDepth);
    }

    class SymbolVisitor
    {
    public:
        virtual ~SymbolVisitor() {}
        virtual void useSymbol (const Symbol&) = 0;
    };

    virtual void visitAllSymbols (SymbolVisitor& visitor, const Scope& scope, int recursionDepth)
    {
        for (int i = getNumInputs(); --i >= 0;)
            getInput(i)->visitAllSymbols (visitor, scope, recursionDepth);
    }

private:
    JUCE_DECLARE_NON_COPYABLE (Term)
};

struct Expression::Helpers
{
    typedef ReferenceCountedObjectPtr<Term> TermPtr;

    static void checkRecursionDepth (const int depth)
    {
        if (depth > 256)
            throw EvaluationError ("Recursive symbol references");
    }

    friend class Expression::Term;

    /** An exception that can be thrown by Expression::evaluate(). */
    class EvaluationError  : public std::exception
    {
    public:
        EvaluationError (const String& desc)  : description (desc)
        {
            DBG ("Expression::EvaluationError: " + description);
        }

        String description;
    };

    class Constant  : public Term
    {
    public:
        Constant (const double val, const bool resolutionTarget)
            : value (val), isResolutionTarget (resolutionTarget) {}

        Type getType() const noexcept                { return constantType; }
        Term* clone() const                          { return new Constant (value, isResolutionTarget); }
        TermPtr resolve (const Scope&, int)          { return this; }
        double toDouble() const                      { return value; }
        TermPtr negated()                            { return new Constant (-value, isResolutionTarget); }

        String toString() const
        {
            String s (value);
            if (isResolutionTarget)
                s = "@" + s;

            return s;
        }

        double value;
        bool isResolutionTarget;
    };

    class BinaryTerm  : public Term
    {
    public:
        BinaryTerm (Term* const l, Term* const r) : left (l), right (r)
        {
            jassert (l != nullptr && r != nullptr);
        }

        int getInputIndexFor (const Term* possibleInput) const
        {
            return possibleInput == left ? 0 : (possibleInput == right ? 1 : -1);
        }

        Type getType() const noexcept       { return operatorType; }
        int getNumInputs() const            { return 2; }
        Term* getInput (int index) const    { return index == 0 ? left.get() : (index == 1 ? right.get() : 0); }

        virtual double performFunction (double left, double right) const = 0;
        virtual void writeOperator (String& dest) const = 0;

        TermPtr resolve (const Scope& scope, int recursionDepth)
        {
            return new Constant (performFunction (left ->resolve (scope, recursionDepth)->toDouble(),
                                                  right->resolve (scope, recursionDepth)->toDouble()), false);
        }

        String toString() const
        {
            String s;

            const int ourPrecendence = getOperatorPrecedence();
            if (left->getOperatorPrecedence() > ourPrecendence)
                s << '(' << left->toString() << ')';
            else
                s = left->toString();

            writeOperator (s);

            if (right->getOperatorPrecedence() >= ourPrecendence)
                s << '(' << right->toString() << ')';
            else
                s << right->toString();

            return s;
        }

    protected:
        const TermPtr left, right;

        TermPtr createDestinationTerm (const Scope& scope, const Term* input, double overallTarget, Term* topLevelTerm) const
        {
            jassert (input == left || input == right);
            if (input != left && input != right)
                return TermPtr();

            if (const Term* const dest = findDestinationFor (topLevelTerm, this))
                return dest->createTermToEvaluateInput (scope, this, overallTarget, topLevelTerm);

            return new Constant (overallTarget, false);
        }
    };

    class SymbolTerm  : public Term
    {
    public:
        explicit SymbolTerm (const String& sym) : symbol (sym) {}

        TermPtr resolve (const Scope& scope, int recursionDepth)
        {
            checkRecursionDepth (recursionDepth);
            return scope.getSymbolValue (symbol).term->resolve (scope, recursionDepth + 1);
        }

        Type getType() const noexcept   { return symbolType; }
        Term* clone() const             { return new SymbolTerm (symbol); }
        String toString() const         { return symbol; }
        String getName() const          { return symbol; }

        void visitAllSymbols (SymbolVisitor& visitor, const Scope& scope, int recursionDepth)
        {
            checkRecursionDepth (recursionDepth);
            visitor.useSymbol (Symbol (scope.getScopeUID(), symbol));
            scope.getSymbolValue (symbol).term->visitAllSymbols (visitor, scope, recursionDepth + 1);
        }

        void renameSymbol (const Symbol& oldSymbol, const String& newName, const Scope& scope, int /*recursionDepth*/)
        {
            if (oldSymbol.symbolName == symbol && scope.getScopeUID() == oldSymbol.scopeUID)
                symbol = newName;
        }

        String symbol;
    };

    class Function  : public Term
    {
    public:
        explicit Function (const String& name)  : functionName (name) {}

        Function (const String& name, const Array<Expression>& params)
            : functionName (name), parameters (params)
        {}

        Type getType() const noexcept   { return functionType; }
        Term* clone() const             { return new Function (functionName, parameters); }
        int getNumInputs() const        { return parameters.size(); }
        Term* getInput (int i) const    { return parameters.getReference(i).term; }
        String getName() const          { return functionName; }

        TermPtr resolve (const Scope& scope, int recursionDepth)
        {
            checkRecursionDepth (recursionDepth);
            double result = 0;
            const int numParams = parameters.size();
            if (numParams > 0)
            {
                HeapBlock<double> params ((size_t) numParams);
                for (int i = 0; i < numParams; ++i)
                    params[i] = parameters.getReference(i).term->resolve (scope, recursionDepth + 1)->toDouble();

                result = scope.evaluateFunction (functionName, params, numParams);
            }
            else
            {
                result = scope.evaluateFunction (functionName, nullptr, 0);
            }

            return new Constant (result, false);
        }

        int getInputIndexFor (const Term* possibleInput) const
        {
            for (int i = 0; i < parameters.size(); ++i)
                if (parameters.getReference(i).term == possibleInput)
                    return i;

            return -1;
        }

        String toString() const
        {
            if (parameters.size() == 0)
                return functionName + "()";

            String s (functionName + " (");

            for (int i = 0; i < parameters.size(); ++i)
            {
                s << parameters.getReference(i).term->toString();

                if (i < parameters.size() - 1)
                    s << ", ";
            }

            s << ')';
            return s;
        }

        const String functionName;
        Array<Expression> parameters;
    };

    class DotOperator  : public BinaryTerm
    {
    public:
        DotOperator (SymbolTerm* const l, Term* const r)  : BinaryTerm (l, r) {}

        TermPtr resolve (const Scope& scope, int recursionDepth)
        {
            checkRecursionDepth (recursionDepth);

            EvaluationVisitor visitor (right, recursionDepth + 1);
            scope.visitRelativeScope (getSymbol()->symbol, visitor);
            return visitor.output;
        }

        Term* clone() const                             { return new DotOperator (getSymbol(), right); }
        String getName() const                          { return "."; }
        int getOperatorPrecedence() const               { return 1; }
        void writeOperator (String& dest) const         { dest << '.'; }
        double performFunction (double, double) const   { return 0.0; }

        void visitAllSymbols (SymbolVisitor& visitor, const Scope& scope, int recursionDepth)
        {
            checkRecursionDepth (recursionDepth);
            visitor.useSymbol (Symbol (scope.getScopeUID(), getSymbol()->symbol));

            SymbolVisitingVisitor v (right, visitor, recursionDepth + 1);

            try
            {
                scope.visitRelativeScope (getSymbol()->symbol, v);
            }
            catch (...) {}
        }

        void renameSymbol (const Symbol& oldSymbol, const String& newName, const Scope& scope, int recursionDepth)
        {
            checkRecursionDepth (recursionDepth);
            getSymbol()->renameSymbol (oldSymbol, newName, scope, recursionDepth);

            SymbolRenamingVisitor visitor (right, oldSymbol, newName, recursionDepth + 1);

            try
            {
                scope.visitRelativeScope (getSymbol()->symbol, visitor);
            }
            catch (...) {}
        }

    private:
        class EvaluationVisitor  : public Scope::Visitor
        {
        public:
            EvaluationVisitor (const TermPtr& t, const int recursion)
                : input (t), output (t), recursionCount (recursion) {}

            void visit (const Scope& scope)   { output = input->resolve (scope, recursionCount); }

            const TermPtr input;
            TermPtr output;
            const int recursionCount;

        private:
            JUCE_DECLARE_NON_COPYABLE (EvaluationVisitor)
        };

        class SymbolVisitingVisitor  : public Scope::Visitor
        {
        public:
            SymbolVisitingVisitor (const TermPtr& t, SymbolVisitor& v, const int recursion)
                : input (t), visitor (v), recursionCount (recursion) {}

            void visit (const Scope& scope)   { input->visitAllSymbols (visitor, scope, recursionCount); }

        private:
            const TermPtr input;
            SymbolVisitor& visitor;
            const int recursionCount;

            JUCE_DECLARE_NON_COPYABLE (SymbolVisitingVisitor)
        };

        class SymbolRenamingVisitor   : public Scope::Visitor
        {
        public:
            SymbolRenamingVisitor (const TermPtr& t, const Expression::Symbol& symbol_, const String& newName_, const int recursionCount_)
                : input (t), symbol (symbol_), newName (newName_), recursionCount (recursionCount_)  {}

            void visit (const Scope& scope)   { input->renameSymbol (symbol, newName, scope, recursionCount); }

        private:
            const TermPtr input;
            const Symbol& symbol;
            const String newName;
            const int recursionCount;

            JUCE_DECLARE_NON_COPYABLE (SymbolRenamingVisitor)
        };

        SymbolTerm* getSymbol() const  { return static_cast<SymbolTerm*> (left.get()); }

        JUCE_DECLARE_NON_COPYABLE (DotOperator)
    };

    class Negate  : public Term
    {
    public:
        explicit Negate (const TermPtr& t) : input (t)
        {
            jassert (t != nullptr);
        }

        Type getType() const noexcept                           { return operatorType; }
        int getInputIndexFor (const Term* possibleInput) const  { return possibleInput == input ? 0 : -1; }
        int getNumInputs() const                                { return 1; }
        Term* getInput (int index) const                        { return index == 0 ? input.get() : nullptr; }
        Term* clone() const                                     { return new Negate (input->clone()); }

        TermPtr resolve (const Scope& scope, int recursionDepth)
        {
            return new Constant (-input->resolve (scope, recursionDepth)->toDouble(), false);
        }

        String getName() const          { return "-"; }
        TermPtr negated()               { return input; }

        TermPtr createTermToEvaluateInput (const Scope& scope, const Term* t, double overallTarget, Term* topLevelTerm) const
        {
            ignoreUnused (t);
            jassert (t == input);

            const Term* const dest = findDestinationFor (topLevelTerm, this);

            return new Negate (dest == nullptr ? new Constant (overallTarget, false)
                                               : dest->createTermToEvaluateInput (scope, this, overallTarget, topLevelTerm));
        }

        String toString() const
        {
            if (input->getOperatorPrecedence() > 0)
                return "-(" + input->toString() + ")";

            return "-" + input->toString();
        }

    private:
        const TermPtr input;
    };

    class Add  : public BinaryTerm
    {
    public:
        Add (Term* const l, Term* const r) : BinaryTerm (l, r) {}

        Term* clone() const                     { return new Add (left->clone(), right->clone()); }
        double performFunction (double lhs, double rhs) const    { return lhs + rhs; }
        int getOperatorPrecedence() const       { return 3; }
        String getName() const                  { return "+"; }
        void writeOperator (String& dest) const { dest << " + "; }

        TermPtr createTermToEvaluateInput (const Scope& scope, const Term* input, double overallTarget, Term* topLevelTerm) const
        {
            const TermPtr newDest (createDestinationTerm (scope, input, overallTarget, topLevelTerm));
            if (newDest == nullptr)
                return TermPtr();

            return new Subtract (newDest, (input == left ? right : left)->clone());
        }

    private:
        JUCE_DECLARE_NON_COPYABLE (Add)
    };

    class Subtract  : public BinaryTerm
    {
    public:
        Subtract (Term* const l, Term* const r) : BinaryTerm (l, r) {}

        Term* clone() const                     { return new Subtract (left->clone(), right->clone()); }
        double performFunction (double lhs, double rhs) const    { return lhs - rhs; }
        int getOperatorPrecedence() const       { return 3; }
        String getName() const                  { return "-"; }
        void writeOperator (String& dest) const { dest << " - "; }

        TermPtr createTermToEvaluateInput (const Scope& scope, const Term* input, double overallTarget, Term* topLevelTerm) const
        {
            const TermPtr newDest (createDestinationTerm (scope, input, overallTarget, topLevelTerm));
            if (newDest == nullptr)
                return TermPtr();

            if (input == left)
                return new Add (newDest, right->clone());

            return new Subtract (left->clone(), newDest);
        }

    private:
        JUCE_DECLARE_NON_COPYABLE (Subtract)
    };

    class Multiply  : public BinaryTerm
    {
    public:
        Multiply (Term* const l, Term* const r) : BinaryTerm (l, r) {}

        Term* clone() const                     { return new Multiply (left->clone(), right->clone()); }
        double performFunction (double lhs, double rhs) const    { return lhs * rhs; }
        String getName() const                  { return "*"; }
        void writeOperator (String& dest) const { dest << " * "; }
        int getOperatorPrecedence() const       { return 2; }

        TermPtr createTermToEvaluateInput (const Scope& scope, const Term* input, double overallTarget, Term* topLevelTerm) const
        {
            const TermPtr newDest (createDestinationTerm (scope, input, overallTarget, topLevelTerm));
            if (newDest == nullptr)
                return TermPtr();

            return new Divide (newDest, (input == left ? right : left)->clone());
        }

    private:
        JUCE_DECLARE_NON_COPYABLE (Multiply)
    };

    class Divide  : public BinaryTerm
    {
    public:
        Divide (Term* const l, Term* const r) : BinaryTerm (l, r) {}

        Term* clone() const                     { return new Divide (left->clone(), right->clone()); }
        double performFunction (double lhs, double rhs) const    { return lhs / rhs; }
        String getName() const                  { return "/"; }
        void writeOperator (String& dest) const { dest << " / "; }
        int getOperatorPrecedence() const       { return 2; }

        TermPtr createTermToEvaluateInput (const Scope& scope, const Term* input, double overallTarget, Term* topLevelTerm) const
        {
            const TermPtr newDest (createDestinationTerm (scope, input, overallTarget, topLevelTerm));
            if (newDest == nullptr)
                return TermPtr();

            if (input == left)
                return new Multiply (newDest, right->clone());

            return new Divide (left->clone(), newDest);
        }

    private:
        JUCE_DECLARE_NON_COPYABLE (Divide)
    };

    static Term* findDestinationFor (Term* const topLevel, const Term* const inputTerm)
    {
        const int inputIndex = topLevel->getInputIndexFor (inputTerm);
        if (inputIndex >= 0)
            return topLevel;

        for (int i = topLevel->getNumInputs(); --i >= 0;)
        {
            Term* const t = findDestinationFor (topLevel->getInput (i), inputTerm);

            if (t != nullptr)
                return t;
        }

        return nullptr;
    }

    static Constant* findTermToAdjust (Term* const term, const bool mustBeFlagged)
    {
        jassert (term != nullptr);

        if (term->getType() == constantType)
        {
            Constant* const c = static_cast<Constant*> (term);
            if (c->isResolutionTarget || ! mustBeFlagged)
                return c;
        }

        if (term->getType() == functionType)
            return nullptr;

        const int numIns = term->getNumInputs();

        for (int i = 0; i < numIns; ++i)
        {
            Term* const input = term->getInput (i);

            if (input->getType() == constantType)
            {
                Constant* const c = static_cast<Constant*> (input);

                if (c->isResolutionTarget || ! mustBeFlagged)
                    return c;
            }
        }

        for (int i = 0; i < numIns; ++i)
        {
            Constant* const c = findTermToAdjust (term->getInput (i), mustBeFlagged);
            if (c != nullptr)
                return c;
        }

        return nullptr;
    }

    static bool containsAnySymbols (const Term* const t)
    {
        if (t->getType() == Expression::symbolType)
            return true;

        for (int i = t->getNumInputs(); --i >= 0;)
            if (containsAnySymbols (t->getInput (i)))
                return true;

        return false;
    }

    class SymbolCheckVisitor  : public Term::SymbolVisitor
    {
    public:
        SymbolCheckVisitor (const Symbol& symbol_) : wasFound (false), symbol (symbol_) {}
        void useSymbol (const Symbol& s)    { wasFound = wasFound || s == symbol; }

        bool wasFound;

    private:
        const Symbol& symbol;

        JUCE_DECLARE_NON_COPYABLE (SymbolCheckVisitor)
    };

    class SymbolListVisitor  : public Term::SymbolVisitor
    {
    public:
        SymbolListVisitor (Array<Symbol>& list_) : list (list_) {}
        void useSymbol (const Symbol& s)    { list.addIfNotAlreadyThere (s); }

    private:
        Array<Symbol>& list;

        JUCE_DECLARE_NON_COPYABLE (SymbolListVisitor)
    };

    class Parser
    {
    public:
        Parser (String::CharPointerType& stringToParse)  : text (stringToParse)
        {
        }

        TermPtr readUpToComma()
        {
            if (text.isEmpty())
                return new Constant (0.0, false);

            const TermPtr e (readExpression());

            if (e == nullptr || ((! readOperator (",")) && ! text.isEmpty()))
                return parseError ("Syntax error: \"" + String (text) + "\"");

            return e;
        }

        String error;

    private:
        String::CharPointerType& text;

        Term* parseError (const String& message)
        {
            if (error.isEmpty())
                error = message;

            return nullptr;
        }

        static inline bool isDecimalDigit (const juce_wchar c) noexcept
        {
            return c >= '0' && c <= '9';
        }

        bool readChar (const juce_wchar required) noexcept
        {
            if (*text == required)
            {
                ++text;
                return true;
            }

            return false;
        }

        bool readOperator (const char* ops, char* const opType = nullptr) noexcept
        {
            text = text.findEndOfWhitespace();

            while (*ops != 0)
            {
                if (readChar ((juce_wchar) (uint8) *ops))
                {
                    if (opType != nullptr)
                        *opType = *ops;

                    return true;
                }

                ++ops;
            }

            return false;
        }

        bool readIdentifier (String& identifier) noexcept
        {
            text = text.findEndOfWhitespace();
            String::CharPointerType t (text);
            int numChars = 0;

            if (t.isLetter() || *t == '_')
            {
                ++t;
                ++numChars;

                while (t.isLetterOrDigit() || *t == '_')
                {
                    ++t;
                    ++numChars;
                }
            }

            if (numChars > 0)
            {
                identifier = String (text, (size_t) numChars);
                text = t;
                return true;
            }

            return false;
        }

        Term* readNumber() noexcept
        {
            text = text.findEndOfWhitespace();
            String::CharPointerType t (text);

            const bool isResolutionTarget = (*t == '@');
            if (isResolutionTarget)
            {
                ++t;
                t = t.findEndOfWhitespace();
                text = t;
            }

            if (*t == '-')
            {
                ++t;
                t = t.findEndOfWhitespace();
            }

            if (isDecimalDigit (*t) || (*t == '.' && isDecimalDigit (t[1])))
                return new Constant (CharacterFunctions::readDoubleValue (text), isResolutionTarget);

            return nullptr;
        }

        TermPtr readExpression()
        {
            TermPtr lhs (readMultiplyOrDivideExpression());

            char opType;
            while (lhs != nullptr && readOperator ("+-", &opType))
            {
                TermPtr rhs (readMultiplyOrDivideExpression());

                if (rhs == nullptr)
                    return parseError ("Expected expression after \"" + String::charToString ((juce_wchar) (uint8) opType) + "\"");

                if (opType == '+')
                    lhs = new Add (lhs, rhs);
                else
                    lhs = new Subtract (lhs, rhs);
            }

            return lhs;
        }

        TermPtr readMultiplyOrDivideExpression()
        {
            TermPtr lhs (readUnaryExpression());

            char opType;
            while (lhs != nullptr && readOperator ("*/", &opType))
            {
                TermPtr rhs (readUnaryExpression());

                if (rhs == nullptr)
                    return parseError ("Expected expression after \"" + String::charToString ((juce_wchar) (uint8) opType) + "\"");

                if (opType == '*')
                    lhs = new Multiply (lhs, rhs);
                else
                    lhs = new Divide (lhs, rhs);
            }

            return lhs;
        }

        TermPtr readUnaryExpression()
        {
            char opType;
            if (readOperator ("+-", &opType))
            {
                TermPtr e (readUnaryExpression());

                if (e == nullptr)
                    return parseError ("Expected expression after \"" + String::charToString ((juce_wchar) (uint8) opType) + "\"");

                if (opType == '-')
                    e = e->negated();

                return e;
            }

            return readPrimaryExpression();
        }

        TermPtr readPrimaryExpression()
        {
            TermPtr e (readParenthesisedExpression());
            if (e != nullptr)
                return e;

            e = readNumber();
            if (e != nullptr)
                return e;

            return readSymbolOrFunction();
        }

        TermPtr readSymbolOrFunction()
        {
            String identifier;
            if (readIdentifier (identifier))
            {
                if (readOperator ("(")) // method call...
                {
                    Function* const f = new Function (identifier);
                    ScopedPointer<Term> func (f);  // (can't use ScopedPointer<Function> in MSVC)

                    TermPtr param (readExpression());

                    if (param == nullptr)
                    {
                        if (readOperator (")"))
                            return func.release();

                        return parseError ("Expected parameters after \"" + identifier + " (\"");
                    }

                    f->parameters.add (Expression (param));

                    while (readOperator (","))
                    {
                        param = readExpression();

                        if (param == nullptr)
                            return parseError ("Expected expression after \",\"");

                        f->parameters.add (Expression (param));
                    }

                    if (readOperator (")"))
                        return func.release();

                    return parseError ("Expected \")\"");
                }

                if (readOperator ("."))
                {
                    TermPtr rhs (readSymbolOrFunction());

                    if (rhs == nullptr)
                        return parseError ("Expected symbol or function after \".\"");

                    if (identifier == "this")
                        return rhs;

                    return new DotOperator (new SymbolTerm (identifier), rhs);
                }

                // just a symbol..
                jassert (identifier.trim() == identifier);
                return new SymbolTerm (identifier);
            }

            return TermPtr();
        }

        TermPtr readParenthesisedExpression()
        {
            if (! readOperator ("("))
                return TermPtr();

            const TermPtr e (readExpression());
            if (e == nullptr || ! readOperator (")"))
                return TermPtr();

            return e;
        }

        JUCE_DECLARE_NON_COPYABLE (Parser)
    };
};

Expression::Expression()
    : term (new Expression::Helpers::Constant (0, false))
{
}

Expression::~Expression()
{
}

Expression::Expression (Term* t) : term (t)
{
    jassert (term != nullptr);
}

Expression::Expression (const double constant)
    : term (new Expression::Helpers::Constant (constant, false))
{
}

Expression::Expression (const Expression& other)
    : term (other.term)
{
}

Expression& Expression::operator= (const Expression& other)
{
    term = other.term;
    return *this;
}

#if JUCE_COMPILER_SUPPORTS_MOVE_SEMANTICS
Expression::Expression (Expression&& other) noexcept
    : term (static_cast<ReferenceCountedObjectPtr<Term>&&> (other.term))
{
}

Expression& Expression::operator= (Expression&& other) noexcept
{
    term = static_cast<ReferenceCountedObjectPtr<Term>&&> (other.term);
    return *this;
}
#endif

Expression::Expression (const String& stringToParse, String& parseError)
{
    String::CharPointerType text (stringToParse.getCharPointer());
    Helpers::Parser parser (text);
    term = parser.readUpToComma();
    parseError = parser.error;
}

Expression Expression::parse (String::CharPointerType& stringToParse, String& parseError)
{
    Helpers::Parser parser (stringToParse);
    Expression e (parser.readUpToComma());
    parseError = parser.error;
    return e;
}

double Expression::evaluate() const
{
    return evaluate (Expression::Scope());
}

double Expression::evaluate (const Expression::Scope& scope) const
{
    String err;
    return evaluate (scope, err);
}

double Expression::evaluate (const Scope& scope, String& evaluationError) const
{

    return 0;
}

Expression Expression::operator+ (const Expression& other) const  { return Expression (new Helpers::Add (term, other.term)); }
Expression Expression::operator- (const Expression& other) const  { return Expression (new Helpers::Subtract (term, other.term)); }
Expression Expression::operator* (const Expression& other) const  { return Expression (new Helpers::Multiply (term, other.term)); }
Expression Expression::operator/ (const Expression& other) const  { return Expression (new Helpers::Divide (term, other.term)); }
Expression Expression::operator-() const                          { return Expression (term->negated()); }
Expression Expression::symbol (const String& symbol)              { return Expression (new Helpers::SymbolTerm (symbol)); }

Expression Expression::function (const String& functionName, const Array<Expression>& parameters)
{
    return Expression (new Helpers::Function (functionName, parameters));
}

Expression Expression::adjustedToGiveNewResult (const double targetValue, const Expression::Scope& scope) const
{
    ScopedPointer<Term> newTerm (term->clone());

    Helpers::Constant* termToAdjust = Helpers::findTermToAdjust (newTerm, true);

    if (termToAdjust == nullptr)
        termToAdjust = Helpers::findTermToAdjust (newTerm, false);

    if (termToAdjust == nullptr)
    {
        newTerm = new Helpers::Add (newTerm.release(), new Helpers::Constant (0, false));
        termToAdjust = Helpers::findTermToAdjust (newTerm, false);
    }

    jassert (termToAdjust != nullptr);

    if (const Term* parent = Helpers::findDestinationFor (newTerm, termToAdjust))
    {
        if (const Helpers::TermPtr reverseTerm = parent->createTermToEvaluateInput (scope, termToAdjust, targetValue, newTerm))
            termToAdjust->value = Expression (reverseTerm).evaluate (scope);
        else
            return Expression (targetValue);
    }
    else
    {
        termToAdjust->value = targetValue;
    }

    return Expression (newTerm.release());
}

Expression Expression::withRenamedSymbol (const Expression::Symbol& oldSymbol, const String& newName, const Scope& scope) const
{
    jassert (newName.toLowerCase().containsOnly ("abcdefghijklmnopqrstuvwxyz0123456789_"));

    if (oldSymbol.symbolName == newName)
        return *this;

    Expression e (term->clone());
    e.term->renameSymbol (oldSymbol, newName, scope, 0);
    return e;
}

bool Expression::referencesSymbol (const Expression::Symbol& symbolToCheck, const Scope& scope) const
{
    Helpers::SymbolCheckVisitor visitor (symbolToCheck);

    try
    {
        term->visitAllSymbols (visitor, scope, 0);
    }
    catch (Helpers::EvaluationError&)
    {}

    return visitor.wasFound;
}

void Expression::findReferencedSymbols (Array<Symbol>& results, const Scope& scope) const
{
    try
    {
        Helpers::SymbolListVisitor visitor (results);
        term->visitAllSymbols (visitor, scope, 0);
    }
    catch (Helpers::EvaluationError&)
    {}
}

String Expression::toString() const                     { return term->toString(); }
bool Expression::usesAnySymbols() const                 { return Helpers::containsAnySymbols (term); }
Expression::Type Expression::getType() const noexcept   { return term->getType(); }
String Expression::getSymbolOrFunction() const          { return term->getName(); }
int Expression::getNumInputs() const                    { return term->getNumInputs(); }
Expression Expression::getInput (int index) const       { return Expression (term->getInput (index)); }

ReferenceCountedObjectPtr<Expression::Term> Expression::Term::negated()
{
    return new Helpers::Negate (this);
}

Expression::Symbol::Symbol (const String& scope, const String& symbol)
    : scopeUID (scope), symbolName (symbol)
{
}

bool Expression::Symbol::operator== (const Symbol& other) const noexcept
{
    return symbolName == other.symbolName && scopeUID == other.scopeUID;
}

bool Expression::Symbol::operator!= (const Symbol& other) const noexcept
{
    return ! operator== (other);
}

Expression::Scope::Scope()  {}
Expression::Scope::~Scope() {}

Expression Expression::Scope::getSymbolValue (const String& symbol) const
{
    if (symbol.isNotEmpty())
        throw Helpers::EvaluationError ("Unknown symbol: " + symbol);

    return Expression();
}

double Expression::Scope::evaluateFunction (const String& functionName, const double* parameters, int numParams) const
{
    if (numParams > 0)
    {
        if (functionName == "min")
        {
            double v = parameters[0];
            for (int i = 1; i < numParams; ++i)
                v = jmin (v, parameters[i]);

            return v;
        }

        if (functionName == "max")
        {
            double v = parameters[0];
            for (int i = 1; i < numParams; ++i)
                v = jmax (v, parameters[i]);

            return v;
        }

        if (numParams == 1)
        {
            if (functionName == "sin")  return std::sin (parameters[0]);
            if (functionName == "cos")  return std::cos (parameters[0]);
            if (functionName == "tan")  return std::tan (parameters[0]);
            if (functionName == "abs")  return std::abs (parameters[0]);
        }
    }

    throw Helpers::EvaluationError ("Unknown function: \"" + functionName + "\"");
}

void Expression::Scope::visitRelativeScope (const String& scopeName, Visitor&) const
{
    throw Helpers::EvaluationError ("Unknown symbol: " + scopeName);
}

String Expression::Scope::getScopeUID() const
{
    return String();
}